home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 7675 / 7675.xpi / chrome / wikilook / content / wikilook.js < prev    next >
Text File  |  2009-11-01  |  384KB  |  10,237 lines

  1. /*************************
  2.  * WikiLook.js
  3.  * Developers(in alphabetical order): David Cognito, TestPilot
  4.  *
  5.  *Credit/licence: all  data  is available from Wikipedia and Wiktionary  sites
  6.  *under  GNU FDL  license.  A big part of used code was written by User  Lupin
  7.  *and modified by hundreds volunteers, it now know as MediaWiki Gadget-popups.
  8.  *InstaView was written by Pedro Fayolle and is available under  BSD  licence.
  9.  *Also, this extension is using code developed by multiple GPL based projects,
  10.  *including, but not limited to  Kitadic,   TotalToolbar,    RadialContext-mz,
  11.  *MediaWiki  and  others.  Special thanks for modifications  and  code donated
  12.  *by Marien Zwart, David Laws,  Onno Ekker,  Andrew Krizhanovsky, Conrad Irwin
  13.  *and others.
  14.  *************************/
  15.  
  16. // var popupVersion="en:MediaWiki:Gadget-popups.js " + /*/{{subst:Selfsubst/now string|js|/*/ "2009-05-04 15:11:41 (UTC)" /*/}}/*/;
  17. // STARTFILE: main.js
  18. // **********************************************************************
  19. // **                                                                  **
  20. // ** if you do edit this file, be sure that your editor recognizes it **
  21. // ** as utf8, or the weird and wonderful characters in the namespaces **
  22. // **   below will be completely broken. You can check with the show   **
  23. // **            changes button before submitting the edit.            **
  24. // **         test: [a-zA-Z╨░-╤Å╨É-╨»├á-┼╛╬æ-ß┐Ñ╘▒-╓çπüü-πâ╢Σ┐â-µ¥üπä▒φòÿΓü┐'ΓÇÖ┼┐├ü├ë├ì]           **
  25. // **                                                                  **
  26. // ********************************************************************** 
  27.  
  28. //////////////////////////////////////////////////
  29. // Globals
  30. //
  31. // Trying to shove as many of these as possible into the pg (popup globals) object
  32.  
  33. function pg(){}; // dummy to stop errors
  34. window.pg = {
  35.     re: {},               // regexps
  36.     ns: {},               // namespaces
  37.     string: {},           // translatable strings
  38.     wiki: {},             // local site info
  39.     misc: {},             // YUCK PHOOEY
  40.     option: {},           // options, see newOption etc
  41.     optionDefault: {},    // default option values
  42.     flag: {},             // misc flags
  43.     cache: {},            // page and image cache
  44.     structures: {},       // navlink structures
  45.     timer: {},            // all sorts of timers (too damn many)
  46.     counter: {},          // .. and all sorts of counters
  47.     current: {},          // state info
  48.     endoflist: null
  49. };
  50. window.pop = {          // wrap various functions in here
  51.     init: {},
  52.     util: {},
  53.     endoflist: null
  54. };
  55. function popupsReady() {
  56.     if (!window.pg) { return false; }
  57.     if (!pg.flag) { return false; }
  58.     if (!pg.flag.finishedLoading) { return false; }
  59.     return true;
  60. }
  61.  
  62. /// Local Variables: ///
  63. /// mode:c ///
  64. /// End: ///
  65. // ENDFILE: main.js
  66. // STARTFILE: actions.js
  67. function setupTooltips(container, remove, force, popData) {
  68.     log('setupTooltips, container='+container+', remove='+remove);
  69.     if (!container) {
  70. //<NOLITE>
  71.         // the main initial call
  72.         if (getValueOf('popupOnEditSelection') && window.doSelectionPopup && document && document.editform && document.editform.wpTextbox1) {
  73.             document.editform.wpTextbox1.onmouseup=doSelectionPopup;
  74.         }
  75. //</NOLITE>
  76.         // article/content is a structure-dependent thing
  77.         container = defaultPopupsContainer();
  78.     }
  79.  
  80.     if (!remove && !force && container.ranSetupTooltipsAlready) { return; }
  81.     container.ranSetupTooltipsAlready = !remove;
  82.  
  83.     var anchors;
  84.     anchors=container.getElementsByTagName('A');
  85.     setupTooltipsLoop(anchors, 0, 250, 100, remove, popData);
  86.     WikiLook_Overlay._DIVrepositioned=false;
  87. }
  88.  
  89. function defaultPopupsContainer() {
  90.     if (getValueOf('popupOnlyArticleLinks')) {
  91.         return content.document.getElementById('article') ||
  92.             content.document.getElementById('content') || 
  93.             content.document.getElementById('mw_content') || document;
  94.     }
  95.     return  document;
  96. }
  97.  
  98. function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) {
  99.     log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments));
  100.     var finish=begin+howmany;
  101.     var loopend = min(finish, anchors.length);
  102.     var j=loopend - begin;
  103.     log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin +
  104.          ', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove);
  105.     var doTooltip= remove ? removeTooltip : addTooltip;
  106.     // try a faster (?) loop construct
  107.     if (j > 0) {
  108.         do {
  109.             var a=anchors[loopend - j];
  110.             if (!a || !a.href) {
  111.                 log('got null anchor at index ' + loopend - j);
  112.                 continue;
  113.             }
  114.             doTooltip(a, popData);
  115.         } while (--j);
  116.     }
  117.     if (finish < anchors.length) {
  118.         setTimeout(function() {
  119.                 setupTooltipsLoop(anchors,finish,howmany,sleep,remove,popData);},
  120.             sleep);
  121.     } else {
  122.         if ( !remove && ! getValueOf('popupTocLinks')) { rmTocTooltips(); }
  123.         pg.flag.finishedLoading=true;
  124.     }
  125. }
  126.  
  127. // eliminate popups from the TOC
  128. // This also kills any onclick stuff that used to be going on in the toc
  129. function rmTocTooltips() {
  130.     var toc=content.document.getElementById('toc');
  131.     if (toc) {
  132.         var tocLinks=toc.getElementsByTagName('A');
  133.         var tocLen = tocLinks.length;
  134.         for (j=0; j<tocLen; ++j) {
  135.             removeTooltip(tocLinks[j], true);
  136.         }
  137.     }
  138. }
  139.  
  140. function addTooltip(a, popData) {
  141.     if ( !isPopupLink(a) ) { return; } //ggggggg
  142.     //a.onmouseover=mouseOverWikiLink;
  143.     //a.onmouseout= mouseOutWikiLink;
  144.     //a.onmousedown = killPopup;
  145.     //a.hasPopup = true;
  146.     //a.popData = popData;
  147. }
  148.  
  149. function removeTooltip(a) {
  150.     if ( !a.hasPopup ) { return; }
  151.     a.onmouseover = null;
  152.     a.onmouseout = null;
  153.     if (a.originalTitle) { a.title = a.originalTitle; }
  154.     a.hasPopup=false;
  155. }
  156.  
  157. function removeTitle(a) {
  158.     if (a.originalTitle) { return; }
  159.     a.originalTitle=a.title;
  160.     a.title='';
  161. }
  162.  
  163. function restoreTitle(a) {
  164.     if ( a.title || !a.originalTitle ) { return; }
  165.     a.title = a.originalTitle;
  166.     a.originalTitle='';
  167. }
  168.  
  169. function registerHooks(np) {
  170.     var popupMaxWidth=getValueOf('popupMaxWidth');
  171.  
  172.     if (typeof popupMaxWidth == 'number') {
  173.         var setMaxWidth = function () {
  174.             np.mainDiv.style.maxWidth = popupMaxWidth + 'px';
  175.             np.maxWidth = popupMaxWidth;
  176.  
  177.             // hack for IE
  178.             // see http://www.svendtofte.com/code/max_width_in_ie/
  179.             // use setExpression as documented here on msdn: http://tinyurl dot com/dqljn
  180.  
  181.             if (np.mainDiv.style.setExpression) {
  182.                 np.mainDiv.style.setExpression(
  183.                     'width', 'document.body.clientWidth > ' +
  184.                     popupMaxWidth + ' ? "' +popupMaxWidth + 'px": "auto"');
  185.             }
  186.         };
  187.         np.addHook(setMaxWidth, 'unhide', 'before');
  188.     }
  189. //<NOLITE>
  190.     if (window.addPopupShortcuts && window.rmPopupShortcuts) {
  191.         np.addHook(addPopupShortcuts, 'unhide', 'after');
  192.         np.addHook(rmPopupShortcuts, 'hide', 'before');
  193.     }
  194. //</NOLITE>
  195. }
  196.  
  197.  
  198. function mouseOverWikiLink(evt) {
  199.     if (!window.popupsReady || !window.popupsReady()) { return; }
  200.     if (!evt && window.event) {evt=window.event};
  201.     return mouseOverWikiLink2(this, evt);
  202. }
  203.  
  204. function footnoteTarget(a) {
  205.     var aTitle=Title.fromAnchor(a);
  206.     // We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly
  207.     var anch = aTitle.anchor;
  208.     if ( ! /^(cite_note-|_note-|endnote)/.test(anch) ) { return false;    }
  209.  
  210.     var lTitle=Title.fromURL(location.href);
  211.     if ( lTitle.toString(true) != aTitle.toString(true) ) {    return false; }
  212.  
  213.     var el=content.document.getElementById(anch);
  214.     while ( el && typeof el.nodeName == 'string') {
  215.         var nt = el.nodeName.toLowerCase();
  216.         if ( nt == 'li' ) { return el; }
  217.         else if ( nt == 'body' ) { return false; }
  218.         else if ( el.parentNode ) { el=el.parentNode; }
  219.         else { return false; }
  220.     }
  221.     return false;
  222. }
  223.  
  224. function footnotePreview(x, navpop) {
  225.     setPopupHTML('<hr>' + x.innerHTML, 'popupPreview',  navpop.idNumber,
  226.              getValueOf('popupSubpopups') ? function() {
  227.         setupTooltips(content.document.getElementById('popupPreview' + navpop.idNumber));
  228.     } : null);
  229. }
  230.  
  231. // var modid=0;
  232. // if(!window.opera) { window.opera={postError: console.log}; }
  233.  
  234. function modifierKeyHandler(a) {
  235.     return function(evt) {
  236.         //        opera.postError('modifierKeyHandler called' + (++modid));
  237.         //        opera.postError(''+evt + modid);
  238.         //        for (var i in evt) {
  239.         //            opera.postError('' + modid + ' ' + i + ' ' + evt[i]);
  240.         //        }
  241.         //        opera.postError(''+evt.ctrlKey + modid);
  242.         var mod=getValueOf('popupModifier');
  243.         if (!mod) { return true; }
  244.  
  245.         if (!evt && window.event) {evt=window.event};
  246.         //        opera.postError('And now....'+modid);
  247.         //        opera.postError(''+evt+modid);
  248.         //        opera.postError(''+evt.ctrlKey+modid);
  249.  
  250.         var modPressed = modifierPressed(evt);
  251.         var action = getValueOf('popupModifierAction');
  252.  
  253.         // FIXME: probable bug - modifierPressed should be modPressed below?
  254.         if ( action == 'disable' && modifierPressed ) { return true; }
  255.         if ( action == 'enable' && !modifierPressed ) { return true; }
  256.  
  257.         mouseOverWikiLink2(a, evt);
  258.     };
  259. }
  260.  
  261. function modifierPressed(evt) {
  262.         var mod=getValueOf('popupModifier');
  263.         if (!mod) { return false; }
  264.  
  265.         if (!evt && window.event) {evt=window.event};
  266. //        opera.postError('And now....'+modid);
  267. //        opera.postError(''+evt+modid);
  268. //        opera.postError(''+evt.ctrlKey+modid);
  269.  
  270.         return ( evt && mod && evt[mod.toLowerCase() + 'Key'] );
  271.  
  272. }
  273.  
  274. function dealWithModifier(a,evt) {
  275.     if (!getValueOf('popupModifier')) { return false; }
  276.     var action = getValueOf('popupModifierAction');
  277.     if ( action == 'enable' && !modifierPressed(evt) ||
  278.          action == 'disable' && modifierPressed(evt) ) {
  279.         // if the modifier is needed and not pressed, listen for it until
  280.         // we mouseout of this link.
  281.         restoreTitle(a);
  282.         var addHandler='addEventListener';
  283.         var rmHandler='removeEventListener';
  284.         var on='';
  285.         if (!document.addEventListener) {
  286.             addHandler='attachEvent';
  287.             rmHandler='detachEvent';
  288.             on='on';
  289.         }
  290.         if (!document[addHandler]) { // forget it
  291.             return;
  292.         }
  293.  
  294.         a.modifierKeyHandler=modifierKeyHandler(a);
  295.  
  296.         switch (action) {
  297.         case 'enable':
  298.             document[addHandler](on+'keydown', a.modifierKeyHandler, false);
  299.             a[addHandler](on+'mouseout', function() {
  300.                     document[rmHandler](on+'keydown',
  301.                                 a.modifierKeyHandler, false);
  302.                 }, true);
  303.             break;
  304.         case 'disable':
  305.             document[addHandler](on+'keyup', a.modifierKeyHandler, false);
  306.         }
  307.  
  308.         return true;
  309.     }
  310.     return false;
  311. }
  312.  
  313. function mouseOutWikiLink3(evt) {
  314.     clearTimeout(WikiLook_Overlay._overWikiLink);
  315. }
  316.  
  317. function mouseOverWikiLink3(evt) {
  318.     /*WikiLook_Overlay._divOverWikiLinksEnabled=WikiLookdb_pref.getCharPref("divOverWikiLinksEnabled");
  319.     WikiLook_Overlay._divOverWikiLinksDelay=WikiLookdb_pref.getIntPref("divOverWikiLinksDelay");*/    
  320.     WikiLook_Overlay.grabOverWikiLinks();
  321.     
  322.     if (evt.target.href==null||(!WikiLook_Overlay._divOverWikiLinksEnabled)) return;
  323.  
  324.     if (evt.target.href.indexOf("http://en.wiktionary.org/wiki/")!=-1) { //Native gggggggggggg
  325.         WikiLook_Overlay._currentParser = WikiLookdb_pref.getCharPref("WikiLookShiftParser");
  326.         var article=decodeURI(evt.target.href.substring("http://en.wiktionary.org/wiki/".length, evt.target.href.length));
  327.         if (WikiLook_Overlay._currentWord==article)    return;
  328.         if (article.indexOf("#")!=-1) article=article.substring(0, article.indexOf("#"));
  329.         WikiLook_Overlay._overWikiLinkEvt=evt.target.href;
  330.         WikiLook_Overlay._overWikiLinkWord=article;
  331.         WikiLook_Overlay._overWikiLink=setTimeout(function(){
  332.                 var i=0;
  333.                 while (pg.ns.list[i]!=null) {
  334.                     if (WikiLook_Overlay._overWikiLinkEvt.indexOf("http://en.wiktionary.org/wiki/"+encodeURI(pg.ns.list[i].replace(/ /g,"_"))+":")!=-1) return;
  335.                     ++i;
  336.                 }
  337.                 if (WikiLook_Overlay._overWikiLinkEvt.indexOf("http://en.wiktionary.org/wiki/Wiktionary:")!=-1) return;
  338.                 WikiLook_Overlay._insideDivLookup=true;
  339.                 WikiLook_Overlay._currentWord=WikiLook_Overlay._overWikiLinkWord;
  340.                 WikiLook_Overlay.nativeParser();
  341.         }, WikiLook_Overlay._divOverWikiLinksDelay); 
  342.         return;
  343.     }
  344.     if (evt.target.href.indexOf(WikiLookdb_pref.getCharPref("WikiLookShiftParser")+"/wiki/")!=-1) { //Shift
  345.         WikiLook_Overlay._currentParser = WikiLookdb_pref.getCharPref("WikiLookShiftParser");
  346.         var article=decodeURI(evt.target.href.substring(WikiLook_Overlay._currentParser.length+6, evt.target.href.length));
  347.         if (WikiLook_Overlay._currentWord==article)    return;
  348.         WikiLook_Overlay._overWikiLinkWord=article;
  349.         WikiLook_Overlay._overWikiLinkEvt=evt.target.href;
  350.         WikiLook_Overlay._overWikiLink=setTimeout(function(){
  351.                 WikiLook_Overlay._currentWord=WikiLook_Overlay._overWikiLinkWord;
  352.                 setSiteInfo();
  353.                 setMainRegex();
  354.                 setTitleBase();
  355.                 setNamespaces();
  356.                 setRegexps();
  357.                 var i=0;
  358.                 while (pg.ns.list[i]!=null) {
  359.                     if (WikiLook_Overlay._overWikiLinkEvt.indexOf(WikiLookdb_pref.getCharPref("WikiLookShiftParser")+"/wiki/"+encodeURI(pg.ns.list[i].replace(/ /g,"_"))+":")!=-1) return;
  360.                     ++i;
  361.                 }
  362.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  363.                 WikiLook_Overlay._CSS='<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopsft.css" /> ';
  364.                 a.href=WikiLook_Overlay._overWikiLinkEvt;
  365.                 WikiLook_Overlay._DIVclass='sft';
  366.                 mouseOverWikiLink2(a);
  367.         }, WikiLook_Overlay._divOverWikiLinksDelay); 
  368.         return;
  369.     }
  370.     if (evt.target.href.indexOf(WikiLookdb_pref.getCharPref("WikiLookCtrlParser")+"/wiki/")!=-1) { //Ctrl
  371.         WikiLook_Overlay._currentParser = WikiLookdb_pref.getCharPref("WikiLookCtrlParser");
  372.         var article=decodeURI(evt.target.href.substring(WikiLook_Overlay._currentParser.length+6, evt.target.href.length));
  373.         if (WikiLook_Overlay._currentWord==article)    return;
  374.         WikiLook_Overlay._overWikiLinkWord=article;
  375.         WikiLook_Overlay._overWikiLinkEvt=evt.target.href;
  376.         WikiLook_Overlay._overWikiLink=setTimeout(function(){
  377.                 
  378.                 WikiLook_Overlay._currentWord=WikiLook_Overlay._overWikiLinkWord;
  379.                 setSiteInfo();
  380.                 setMainRegex();
  381.                 setTitleBase();
  382.                 setNamespaces();
  383.                 setRegexps();
  384.                 var i=0;
  385.                 while (pg.ns.list[i]!=null) {
  386.                     if (WikiLook_Overlay._overWikiLinkEvt.indexOf(WikiLookdb_pref.getCharPref("WikiLookCtrlParser")+"/wiki/"+encodeURI(pg.ns.list[i].replace(/ /g,"_"))+":")!=-1) return;
  387.                     ++i;
  388.                 }
  389.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  390.                 WikiLook_Overlay._CSS='<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopctl.css" /> '; //
  391.                 a.href=WikiLook_Overlay._overWikiLinkEvt;
  392.                 WikiLook_Overlay._DIVclass='ctl';//
  393.                 mouseOverWikiLink2(a);
  394.         }, WikiLook_Overlay._divOverWikiLinksDelay); 
  395.         return;
  396.     }
  397.     if (evt.target.href.indexOf(WikiLookdb_pref.getCharPref("WikiLookAltParser")+"/wiki/")!=-1) { //Alt
  398.         WikiLook_Overlay._currentParser = WikiLookdb_pref.getCharPref("WikiLookAltParser");
  399.         var article=decodeURI(evt.target.href.substring(WikiLook_Overlay._currentParser.length+6, evt.target.href.length));
  400.         if (WikiLook_Overlay._currentWord==article)    return;
  401.         WikiLook_Overlay._overWikiLinkWord=article;
  402.         WikiLook_Overlay._overWikiLinkEvt=evt.target.href;
  403.         WikiLook_Overlay._overWikiLink=setTimeout(function(){
  404.                 WikiLook_Overlay._currentWord=WikiLook_Overlay._overWikiLinkWord;
  405.                 setSiteInfo();
  406.                 setMainRegex();
  407.                 setTitleBase();
  408.                 setNamespaces();
  409.                 setRegexps();
  410.                 var i=0;
  411.                 while (pg.ns.list[i]!=null) {
  412.                     if (WikiLook_Overlay._overWikiLinkEvt.indexOf(WikiLookdb_pref.getCharPref("WikiLookAltParser")+"/wiki/"+encodeURI(pg.ns.list[i].replace(/ /g,"_"))+":")!=-1) return;
  413.                     ++i;
  414.                 }
  415.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  416.                 WikiLook_Overlay._CSS='<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopalt.css" /> ';
  417.                 a.href=WikiLook_Overlay._overWikiLinkEvt;
  418.                 WikiLook_Overlay._DIVclass='alt';
  419.                 mouseOverWikiLink2(a);
  420.         }, WikiLook_Overlay._divOverWikiLinksDelay);  
  421.         return;
  422.     }
  423.     if (evt.target.href.indexOf(WikiLookdb_pref.getCharPref("WikiLookMouselookParser")+"/wiki/")!=-1) {  //Mouse 
  424.         WikiLook_Overlay._currentParser = WikiLookdb_pref.getCharPref("WikiLookMouselookParser");
  425.         var article=decodeURI(evt.target.href.substring(WikiLook_Overlay._currentParser.length+6, evt.target.href.length));
  426.         if (WikiLook_Overlay._currentWord==article)    return;
  427.         WikiLook_Overlay._overWikiLinkWord=article;
  428.         WikiLook_Overlay._overWikiLinkEvt=evt.target.href;
  429.         WikiLook_Overlay._overWikiLink=setTimeout(function(){
  430.                 WikiLook_Overlay._currentWord=WikiLook_Overlay._overWikiLinkWord;
  431.                 setSiteInfo();
  432.                 setMainRegex();
  433.                 setTitleBase();
  434.                 setNamespaces();
  435.                 setRegexps();
  436.                 var i=0;
  437.                 while (pg.ns.list[i]!=null) {
  438.                     if (WikiLook_Overlay._overWikiLinkEvt.indexOf(WikiLookdb_pref.getCharPref("WikiLookMouselookParser")+"/wiki/"+encodeURI(pg.ns.list[i].replace(/ /g,"_"))+":")!=-1) return;
  439.                     ++i;
  440.                 }
  441.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  442.                 WikiLook_Overlay._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopmic.css" /> ';
  443.                 a.href=WikiLook_Overlay._overWikiLinkEvt;
  444.                 WikiLook_Overlay._DIVclass='mic';
  445.                 mouseOverWikiLink2(a);
  446.         }, WikiLook_Overlay._divOverWikiLinksDelay);  
  447.         return;
  448.     }
  449.  
  450.  
  451. }
  452.  
  453. function mouseOverWikiLink2(a, evt) {
  454.     if (dealWithModifier(a,evt)) { return; }
  455.     if ( getValueOf('removeTitles') ) { removeTitle(a); }
  456.     if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; }
  457.     pg.current.link=a;
  458.  
  459.     if (getValueOf('simplePopups') && pg.option.popupStructure===null) {
  460.         // reset *default value* of popupStructure
  461.         setDefault('popupStructure', 'original');
  462.     }
  463.  
  464.     var article=(new Title()).fromAnchor(a);
  465.     // set global variable (ugh) to hold article (wikipage)
  466.     pg.current.article = article;
  467.     if (pg.timer.image !== null) {
  468.         clearInterval(pg.timer.image);
  469.         pg.timer.image=null;
  470.         pg.counter.checkImages=0;
  471.     }
  472.  
  473.     if (!a.navpopup) {
  474.         // FIXME: this doesn't behave well if you mouse out of a popup
  475.         // directly into a link with the same href
  476.         if (pg.current.linksHash[a.href] && false) {
  477.             a.navpopup = pg.current.linksHash[a.href];
  478.         }
  479.         else {
  480.             a.navpopup=newNavpopup(a, article);
  481.             pg.current.linksHash[a.href] = a.navpopup;
  482.             pg.current.links.push(a);
  483.         }
  484.     }
  485.     if (a.navpopup.pending===null || a.navpopup.pending!==0) {
  486.         // either fresh popups or those with unfinshed business are redone from scratch
  487.         simplePopupContent(a, article);
  488.     }
  489.     a.navpopup.showSoonIfStable(a.navpopup.delay);
  490.  
  491.     getValueOf('popupInitialWidth');
  492.  
  493.     clearInterval(pg.timer.checkPopupPosition);
  494.     pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600);
  495.  
  496.     if(getValueOf('simplePopups')) {
  497.         if (getValueOf('popupPreviewButton') && !a.simpleNoMore) {
  498.             var d=document.createElementNS("http://www.w3.org/1999/xhtml",'div');
  499.             d.className='popupPreviewButtonDiv';
  500.             var s=document.createElementNS("http://www.w3.org/1999/xhtml",'span');
  501.             d.appendChild(s);
  502.             s.className='popupPreviewButton';
  503.             s['on' + getValueOf('popupPreviewButtonEvent')] = function() {
  504.                 a.simpleNoMore=true;
  505.                 nonsimplePopupContent(a,article);
  506.             }
  507.             s.innerHTML=popupString('show preview');
  508.             setPopupHTML(d, 'popupPreview', a.navpopup.idNumber);
  509.         }
  510.         return;
  511.     }
  512.  
  513.     if (a.navpopup.pending!==0 ) {
  514.         nonsimplePopupContent(a, article);
  515.     }
  516. }
  517.  
  518. // simplePopupContent: the content that is shown even when simplePopups is true
  519. function simplePopupContent(a, article) {
  520.     /* FIXME hack */ a.navpopup.hasPopupMenu=false;
  521.     a.navpopup.setInnerHTML(popupHTML(a));
  522.     fillEmptySpans({navpopup:a.navpopup});
  523.  
  524.     var dragHandle = getValueOf('popupDragHandle') || null;
  525.     if (dragHandle && dragHandle != 'all') {
  526.         dragHandle += a.navpopup.idNumber;
  527.     }
  528.     setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150);
  529.  
  530. //<NOLITE>
  531.     if (getValueOf('popupRedlinkRemoval') && a.className=='new') {
  532.         setPopupHTML('<br>'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber);
  533.     }
  534. //</NOLITE>
  535. }
  536.  
  537. function debugData(navpopup) {
  538.     if(getValueOf('popupDebugging') && navpopup.idNumber) {
  539.         setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending,
  540.                  'popupError', navpopup.idNumber);
  541.     }
  542. }
  543.  
  544. function newNavpopup(a, article) {
  545.     var navpopup = new Navpopup();
  546.     navpopup.fuzz=5;
  547.     navpopup.delay=getValueOf('popupDelay')*1000;
  548.     // increment global counter now
  549.     navpopup.idNumber = ++pg.idNumber;
  550.     navpopup.parentAnchor = a;
  551.     navpopup.parentPopup = (a.popData && a.popData.owner);
  552.     navpopup.article = article;
  553.     registerHooks(navpopup);
  554.     return navpopup;
  555. }
  556.  
  557.  
  558. function nonsimplePopupContent(a, article) {
  559.     var diff=null, history=null;
  560.     var params=parseParams(a.href);
  561.     var oldid=(typeof params.oldid=='undefined' ? null : params.oldid);
  562. //<NOLITE>
  563.     if(getValueOf('popupPreviewDiffs') && window.loadDiff) {
  564.         diff=params.diff;
  565.     }
  566.     if(getValueOf('popupPreviewHistory')) {
  567.         history=(params.action=='history');
  568.     }
  569. //</NOLITE>
  570.     a.navpopup.pending=0;
  571.     var x;
  572.     pg.misc.gImage=null;
  573.     if (x=footnoteTarget(a)) {
  574.         footnotePreview(x, a.navpopup);
  575. //<NOLITE>
  576.     } else if ( diff || diff === 0 ) {
  577.         loadDiff(article, oldid, diff, a.navpopup);
  578.     } else if ( history ) {
  579.         loadAPIPreview('history', article, a.navpopup);
  580.     } else if ( pg.re.contribs.test(a.href) ) {
  581.         loadAPIPreview('contribs', article, a.navpopup);
  582.     } else if ( pg.re.backlinks.test(a.href) ) {
  583.         loadAPIPreview('backlinks', article, a.navpopup);
  584.     } else if ( // FIXME should be able to get all preview combinations with options
  585.         article.namespace()==pg.ns.image &&
  586.         ( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) )
  587.         ) {
  588.         loadAPIPreview('imagepagepreview', article, a.navpopup);
  589.         loadImages(article);
  590. //</NOLITE>
  591.     } else {
  592.         if (article.namespace() == pg.ns.category &&
  593.                 getValueOf('popupCategoryMembers')) {
  594.             loadAPIPreview('category', article, a.navpopup);
  595.         } else if ((article.namespace() == pg.ns.user || article.namespace() == pg.ns.usertalk) &&
  596.                 getValueOf('popupUserInfo')) {
  597.             loadAPIPreview('userinfo', article, a.navpopup);
  598.         }
  599.         startArticlePreview(article, oldid, a.navpopup);
  600.     }
  601. }
  602.  
  603. function pendingNavpopTask(navpop) {
  604.     if (navpop && navpop.pending===null) { navpop.pending=0; }
  605.     ++navpop.pending;
  606.     debugData(navpop);
  607. }
  608.  
  609. function completedNavpopTask(navpop) {
  610.     if (navpop && navpop.pending) { --navpop.pending; }
  611.     debugData(navpop);
  612. }
  613.  
  614. function startArticlePreview(article, oldid, navpop) {
  615.     navpop.redir=0;
  616.     loadPreview(article, oldid, navpop);
  617. }
  618.  
  619. function loadPreview(article, oldid, navpop) {
  620.     pendingNavpopTask(navpop);
  621.     if (!navpop.redir) { navpop.originalArticle=article; }
  622.     if (!navpop.visible && getValueOf('popupLazyDownloads')) {
  623.         var id=(navpop.redir) ? 'DOWNLOAD_PREVIEW_REDIR_HOOK' : 'DOWNLOAD_PREVIEW_HOOK';
  624.         navpop.addHook(function() {
  625.                 getWiki(article, insertPreview, oldid, navpop);
  626.                 return true; }, 'unhide', 'before', id);
  627.     } else {
  628.         getWiki(article, insertPreview, oldid, navpop);
  629.     }
  630. }
  631.  
  632. function loadPreviewFromRedir(redirMatch, navpop) {
  633.     // redirMatch is a regex match
  634.     var target = new Title().fromWikiText(redirMatch[2]);
  635.     // overwrite (or add) anchor from original target
  636.     // mediawiki does overwrite; eg [[User:Lupin/foo3#Done]]
  637.     if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; }
  638.     var trailingRubbish=redirMatch[4];
  639.     navpop.redir++;
  640.     navpop.redirTarget=target;
  641. //<NOLITE>
  642.     if (window.redirLink) {
  643.         var warnRedir = redirLink(target, navpop.article);
  644.         setPopupHTML(warnRedir, 'popupWarnRedir', navpop.idNumber);
  645.     }
  646. //</NOLITE>
  647.     navpop.article=target;
  648.     fillEmptySpans({redir: true, redirTarget: target, navpopup:navpop});
  649.     return loadPreview(target, null,  navpop);
  650. }
  651.  
  652. function insertPreview(download) {
  653.     if (!download.owner) { return; }
  654.  
  655.     var redirMatch = pg.re.redirect.exec(download.data);
  656.     if (download.owner.redir===0 && redirMatch) {
  657.         completedNavpopTask(download.owner);
  658.         loadPreviewFromRedir(redirMatch, download.owner);
  659.         return;
  660.     }
  661.  
  662.     if (download.owner.visible || !getValueOf('popupLazyPreviews')) {
  663.         insertPreviewNow(download);
  664.     } else {
  665.         var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK';
  666.         download.owner.addHook( function(){insertPreviewNow(download); return true;},
  667.                     'unhide', 'after', id );
  668.     }
  669. }
  670.  
  671.  
  672. function insertPreviewNow(download) {
  673.     if (!download.owner) { return; }
  674.     var wikiText=download.data;
  675.     wikiText=expandWikiTextPreview(wikiText);
  676.     var navpop=download.owner;
  677.     completedNavpopTask(navpop);
  678.     var art=navpop.redirTarget || navpop.originalArticle;
  679.  
  680. //<NOLITE>
  681.     makeFixDabs(wikiText, navpop);
  682.     if (getValueOf('popupSummaryData') && window.getPageInfo) {
  683.         var info=getPageInfo(wikiText, download);
  684.         setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber);
  685.     }
  686.  
  687.     var imagePage='';
  688.     if (art.namespace()==pg.ns.image) { imagePage=art.toString(); }
  689.     else { imagePage=getValidImageFromWikiText(wikiText); }
  690.     if(imagePage) { loadImages(Title.fromWikiText(imagePage)); }
  691. //</NOLITE>
  692.  
  693.     if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); }
  694.  
  695. }
  696.  
  697. function insertArticlePreview(download, art, navpop) {
  698.     if (download && typeof download.data == typeof ''){
  699.         if (art.namespace()==pg.ns.template && getValueOf('popupPreviewRawTemplates')) {
  700.             // FIXME compare/consolidate with diff escaping code for wikitext
  701.             var h='<hr><tt>' + download.data.entify().split('\\n').join('<br>\\n') + '</tt>';
  702.             setPopupHTML(h, 'popupPreview', navpop.idNumber);
  703.         }
  704.         else {
  705.             var p=prepPreviewmaker(download.data, art, navpop);
  706.             p.showPreview();
  707.         }
  708.     }
  709. }
  710.  
  711. function prepPreviewmaker(data, article, navpop) {
  712.     // deal with tricksy anchors
  713.     var d=anchorize(data, article.anchorString());
  714.     var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]);
  715.     var p=new Previewmaker(d, urlBase, navpop);
  716.     return p;
  717. }
  718.  
  719.  
  720. // Try to imitate the way mediawiki generates HTML anchors from section titles
  721. function anchorize(d, anch) {
  722.     if (!anch) { return d; }
  723.     var anchRe=RegExp('=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+');
  724.     var match=d.match(anchRe);
  725.     if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); }
  726.  
  727.     // now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom
  728.     var lines=d.split('\n');
  729.     for (var i=0; i<lines.length; ++i) {
  730.         lines[i]=lines[i].replace(RegExp('[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}', 'g'), '$2')
  731.             .replace(/'''([^'])/g, '$1').replace(RegExp("''([^'])", 'g'), '$1');
  732.         if (lines[i].match(anchRe)) {
  733.             return d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), '');
  734.         }
  735.     }
  736.     return d;
  737. }
  738.  
  739. function killPopup() {
  740.     if (getValueOf('popupShortcutKeys') && window.rmPopupShortcuts) { rmPopupShortcuts(); }
  741.     if (!pg) { return; }
  742.     pg.current.link && pg.current.link.navpopup && pg.current.link.navpopup.banish();
  743.     pg.current.link=null;
  744.     abortAllDownloads();
  745.     window.stopImagesDownloading && stopImagesDownloading();
  746.     if (pg.timer.checkPopupPosition !== null) {
  747.         clearInterval(pg.timer.checkPopupPosition);
  748.         pg.timer.checkPopupPosition=null;
  749.     }
  750.     if (pg.timer.checkImages !== null) { clearInterval(pg.timer.checkImages); pg.timer.checkImages=null; }
  751.     if (pg.timer.image !== null) { clearInterval(pg.timer.image); pg.timer.image=null; }
  752.     return true; // preserve default action
  753. }
  754. // ENDFILE: actions.js
  755. // STARTFILE: domdrag.js
  756. /**
  757.    @fileoverview
  758.    The {@link Drag} object, which enables objects to be dragged around.
  759.  
  760.    <pre>
  761.    *************************************************
  762.    dom-drag.js
  763.    09.25.2001
  764.    www.youngpup.net
  765.    **************************************************
  766.    10.28.2001 - fixed minor bug where events
  767.    sometimes fired off the handle, not the root.
  768.    *************************************************
  769.    Pared down, some hooks added by [[User:Lupin]]
  770.  
  771.    Copyright Aaron Boodman.
  772.    Saying stupid things daily since March 2001.
  773.    </pre>
  774. */
  775.  
  776. /**
  777.    Creates a new Drag object. This is used to make various DOM elements draggable.
  778.    @constructor
  779. */
  780. function Drag () {
  781.     /**
  782.        Condition to determine whether or not to drag. This function should take one parameter, an Event.
  783.        To disable this, set it to <code>null</code>.
  784.        @type Function
  785.     */
  786.     this.startCondition = null;
  787.     /**
  788.        Hook to be run when the drag finishes. This is passed the final coordinates of
  789.        the dragged object (two integers, x and y). To disables this, set it to <code>null</code>.
  790.        @type Function
  791.     */
  792.     this.endHook = null;
  793. }
  794.  
  795. /**
  796.    Gets an event in a cross-browser manner.
  797.    @param {Event} e
  798.    @private
  799. */
  800. Drag.prototype.fixE = function(e) {
  801.     if (typeof e == 'undefined') { e = window.event; }
  802.     if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; }
  803.     if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; }
  804.     return e;
  805. };
  806. /**
  807.    Initialises the Drag instance by telling it which object you want to be draggable, and what you want to drag it by.
  808.    @param {DOMElement} o The "handle" by which <code>oRoot</code> is dragged.
  809.    @param {DOMElement} oRoot The object which moves when <code>o</code> is dragged, or <code>o</code> if omitted.
  810. */
  811. Drag.prototype.init = function(o, oRoot) {
  812.     var dragObj      = this;
  813.     this.obj = o;
  814.     o.onmousedown    = function(e) { dragObj.start.apply( dragObj, [e]); };
  815.     o.dragging       = false;
  816.     o.draggable      = true;
  817.     o.hmode          = true;
  818.     o.vmode          = true;
  819.  
  820.     o.root = oRoot && oRoot !== null ? oRoot : o ;
  821.  
  822.     if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left   = "0px"; }
  823.     if (isNaN(parseInt(o.root.style.top,  10))) { o.root.style.top    = "0px"; }
  824.  
  825.     o.root.onthisStart  = function(){};
  826.     o.root.onthisEnd    = function(){};
  827.     o.root.onthis       = function(){};
  828. };
  829.  
  830. /**
  831.    Starts the drag.
  832.    @private
  833.    @param {Event} e
  834. */
  835. Drag.prototype.start = function(e) {
  836.     var o = this.obj; // = this;
  837.     e = this.fixE(e);
  838.     if (this.startCondition && !this.startCondition(e)) { return; }
  839.     var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom, 10);
  840.     var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10);
  841.     o.root.onthisStart(x, y);
  842.  
  843.     o.lastMouseX    = e.clientX;
  844.     o.lastMouseY    = e.clientY;
  845.  
  846.     var dragObj      = this;
  847.     o.onmousemoveDefault    = document.onmousemove;
  848.     o.dragging              = true;
  849.     document.onmousemove    = function(e) { dragObj.drag.apply( dragObj, [e] ); };
  850.     document.onmouseup      = function(e) { dragObj.end.apply( dragObj, [e] ); };
  851.     return false;
  852. };
  853. /**
  854.    Does the drag.
  855.    @param {Event} e
  856.    @private
  857. */
  858. Drag.prototype.drag = function(e) {
  859.     e = this.fixE(e);
  860.     var o = this.obj;
  861.  
  862.     var ey    = e.clientY;
  863.     var ex    = e.clientX;
  864.     var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom, 10);
  865.     var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,  10 );
  866.     var nx, ny;
  867.  
  868.     nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
  869.     ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
  870.  
  871.     this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
  872.     this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
  873.     this.obj.lastMouseX    = ex;
  874.     this.obj.lastMouseY    = ey;
  875.  
  876.     this.obj.root.onthis(nx, ny);
  877.     WikiLook_Overlay._DIVrepositioned=true;
  878.     if ((WikiLook_Overlay._divQ[0]!=this.obj.id)&&(WikiLook_Overlay._divQ.indexOf(this.obj.id)!=-1)) {
  879.         WikiLook_Overlay._divQ.splice(WikiLook_Overlay._divQ.indexOf(this.obj.id),1)
  880.         WikiLook_Overlay._divQ.unshift(this.obj.id);
  881.         WikiLook_Overlay._currentDoc.getElementById(this.obj.id).style.zIndex=WikiLook_Overlay._divZIndex + 1;
  882.         ++WikiLook_Overlay._divZIndex; 
  883.     }
  884.     
  885.     return false;
  886. };
  887.  
  888. /**
  889.    Ends the drag.
  890.    @private
  891. */
  892. Drag.prototype.end = function()  {
  893.     document.onmousemove=this.obj.onmousemoveDefault;
  894.     document.onmouseup   = null;
  895.     this.obj.dragging    = false;
  896.     if (this.endHook) {
  897.         this.endHook( parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10),
  898.                   parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10));
  899.     }
  900. };
  901. // ENDFILE: domdrag.js
  902. // STARTFILE: structures.js
  903. //<NOLITE>
  904. pg.structures.original={};
  905. pg.structures.original.popupLayout=function () {
  906.     return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle',
  907.         'popupData', 'popupOtherLinks',
  908.         'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks',
  909.                    'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
  910.         'popupMiscTools', ['popupRedlink'],
  911.         'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
  912. };
  913. pg.structures.original.popupRedirSpans=function () {
  914.     return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks',
  915.         'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'];
  916. };
  917. pg.structures.original.popupTitle=function (x) {
  918.     log ('defaultstructure.popupTitle');
  919.     if (!getValueOf('popupNavLinks')) {
  920.         return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params);
  921.     }
  922.     return '';
  923. };
  924. pg.structures.original.popupTopLinks=function (x) {
  925.     log ('defaultstructure.popupTopLinks');
  926.     if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.params); }
  927.     return '';
  928. };
  929. pg.structures.original.popupImage=function(x) {
  930.     log ('original.popupImage, x.article='+x.article+', x.navpop.idNumber='+x.navpop.idNumber);
  931.     return imageHTML(x.article, x.navpop.idNumber);
  932. };
  933. pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle;
  934. pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks;
  935.  
  936.  
  937. function copyStructure(oldStructure, newStructure) {
  938.     pg.structures[newStructure]={};
  939.     for (var prop in pg.structures[oldStructure]) {
  940.         pg.structures[newStructure][prop]=pg.structures[oldStructure][prop];
  941.     }
  942. }
  943.  
  944. copyStructure('original', 'nostalgia');
  945. pg.structures.nostalgia.popupTopLinks=function(x)  {
  946.     var str='';
  947.     str += '<b><<mainlink|shortcut= >></b>';
  948.  
  949.     // user links
  950.     // contribs - log - count - email - block
  951.     // count only if applicable; block only if popupAdminLinks
  952.     str += 'if(user){<br><<contribs|shortcut=c>>';
  953.     str+='if(wikimedia){*<<count|shortcut=#>>}';
  954.     str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}';
  955.  
  956.     // editing links
  957.     // talkpage   -> edit|new - history - un|watch - article|edit
  958.     // other page -> edit - history - un|watch - talk|edit|new
  959.     var editstr='<<edit|shortcut=e>>';
  960.     var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{'
  961.     + editstr + '}'
  962.     var historystr='<<history|shortcut=h>>';
  963.     var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
  964.  
  965.     str+='<br>if(talk){' +
  966.         editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
  967.         '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' +
  968.         '}else{' + // not a talk page
  969.         editOldidStr + '*' + historystr + '*' + watchstr + '*' +
  970.         '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
  971.         + '}';
  972.  
  973.     // misc links
  974.     str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>';
  975.     str += 'if(admin){<br>}else{*}<<move|shortcut=m>>';
  976.  
  977.     // admin links
  978.     str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' +
  979.     '<<undelete|undeleteShort>>|<<delete|shortcut=d>>}';
  980.     return navlinkStringToHTML(str, x.article, x.params);
  981. };
  982. pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks;
  983.  
  984. /** -- fancy -- **/
  985. copyStructure('original', 'fancy');
  986. pg.structures.fancy.popupTitle=function (x) {
  987.     return navlinkStringToHTML('<font size=+0><<mainlink>></font>',x.article,x.params);
  988. };
  989. pg.structures.fancy.popupTopLinks=function(x) {
  990.     var hist='<<history|shortcut=h|hist>>|<<lastEdit|shortcut=/|last>>if(mainspace_en){|<<editors|shortcut=E|eds>>}';
  991.     var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
  992.     var move='<<move|shortcut=m|move>>';
  993.     return navlinkStringToHTML('if(talk){' +
  994.                    '<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*' +
  995.                    '<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move +
  996.                    '}else{<<edit|shortcut=e>>*' + hist +
  997.                    '*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>' +
  998.                    '*' + watch + '*' + move+'}<br>', x.article, x.params);
  999. };
  1000. pg.structures.fancy.popupOtherLinks=function(x) {
  1001.     var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>';
  1002.     var user='<<contribs|shortcut=c>>if(wikimedia){|<<count|shortcut=#|#>>}';
  1003.     user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+
  1004.     popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}';
  1005.  
  1006.     var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>';
  1007.     return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}' + normal,
  1008.                    x.article, x.params);
  1009. };
  1010. pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle;
  1011. pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks;
  1012. pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks;
  1013.  
  1014.  
  1015. /** -- fancy2 -- **/
  1016. // hack for [[User:MacGyverMagic]]
  1017. copyStructure('fancy', 'fancy2');
  1018. pg.structures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning
  1019.     return '<br>'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),'');
  1020. };
  1021. pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title
  1022.     return ['popupError', 'popupImage', 'popupTitle', 'popupData', 'popupTopLinks', 'popupOtherLinks',
  1023.         'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
  1024.         'popupMiscTools', ['popupRedlink'],
  1025.         'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
  1026. };
  1027.  
  1028. /** -- menus -- **/
  1029. copyStructure('original', 'menus');
  1030. pg.structures.menus.popupLayout=function () {
  1031.     return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks',
  1032.         'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
  1033.         'popupData', 'popupMiscTools', ['popupRedlink'],
  1034.         'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab'];
  1035. };
  1036. function toggleSticky(uid) {
  1037.     var popDiv=content.document.getElementById('navpopup_maindiv'+uid);
  1038.     if (!popDiv) { return; }
  1039.     if (!popDiv.navpopup.sticky) { popDiv.navpopup.stick(); }
  1040.     else {
  1041.         popDiv.navpopup.unstick();
  1042.         popDiv.navpopup.hide();
  1043.     }
  1044. }
  1045. pg.structures.menus.popupTopLinks = function (x, shorter) {
  1046.     // FIXME maybe this stuff should be cached
  1047.     var s=[];
  1048.     var dropdiv='<div class="popup_drop">';
  1049.     var enddiv='</div>';
  1050.     var endspan='</span>';
  1051.     var hist='<<history|shortcut=h>>';
  1052.     if (!shorter) { hist = '<menurow>' + hist +
  1053.             '|<<historyfeed|rss>>if(mainspace_en){|<<editors|shortcut=E>>}</menurow>'; }
  1054.     var lastedit='<<lastEdit|shortcut=/|show last edit>>';
  1055.     var jsHistory='<<lastContrib|last set of edits>><<sinceMe|changes since mine>>';
  1056.     var linkshere='<<whatLinksHere|shortcut=l|what links here>>';
  1057.     var related='<<relatedChanges|shortcut=r|related changes>>';
  1058.     var search='<menurow><<search|shortcut=s>>if(wikimedia){|<<globalsearch|shortcut=g|global>>}' +
  1059.     '|<<google|shortcut=G|web>></menurow>';
  1060.     var watch='<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>';
  1061.     var protect='<menurow><<unprotect|unprotectShort>>|' +
  1062.     '<<protect|shortcut=p>>|<<protectlog|log>></menurow>';
  1063.     var del='<menurow><<undelete|undeleteShort>>|<<delete|shortcut=d>>|' +
  1064.     '<<deletelog|log>></menurow>';
  1065.     var move='<<move|shortcut=m|move page>>';
  1066.     var nullPurge='<menurow><<nullEdit|shortcut=n|null edit>>|<<purge|shortcut=P>></menurow>';
  1067.     var viewOptions='<menurow><<view|shortcut=v>>|<<render|shortcut=S>>|<<raw>></menurow>';
  1068.     var editRow='if(oldid){' +
  1069.     '<menurow><<edit|shortcut=e>>|<<editOld|shortcut=e|this revision>></menurow>' +
  1070.     '<menurow><<revert|shortcut=v>>|<<undo>></menurow>' + '}else{<<edit|shortcut=e>>}';
  1071.     var markPatrolled='if(rcid){<<markpatrolled|mark patrolled>>}';
  1072.     var newTopic='if(talk){<<new|shortcut=+|new topic>>}';
  1073.     var protectDelete='if(admin){' + protect + del + '}';
  1074.     s.push("<a href='javascript:void(0);'><img id='confDialog' style='border-style: none' title='Click here for configuration dialog.' src='chrome://wikilook/skin/config.png'></a> " + enddiv)       
  1075.     if (getValueOf('popupActionsMenu')) {
  1076.         s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions'));
  1077.     } else {
  1078.         s.push( dropdiv + '<<mainlink>>');
  1079.     }
  1080.     s.push( '<menu>')
  1081.     s.push( editRow + markPatrolled + newTopic + hist + lastedit )
  1082.     if (!shorter) { s.push(jsHistory); }
  1083.     s.push( move + linkshere + related)
  1084.     if (!shorter) { s.push(nullPurge + search); }
  1085.     if (!shorter) { s.push(viewOptions); }
  1086.     s.push('<hr>' + watch + protectDelete);
  1087.     s.push('<hr>' +
  1088.            'if(talk){<<article|shortcut=a|view article>><<editArticle|edit article>>}' +
  1089.            'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' +
  1090.            '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv);
  1091.     // user menu starts here
  1092.     var email='<<email|shortcut=E|email user>>';
  1093.     var contribs=    'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>if(wikimedia){</menurow>}' +
  1094.     'if(admin){<menurow><<deletedContribs>></menurow>}';
  1095.  
  1096.  
  1097.     s.push('if(user){*' + dropdiv + menuTitle('user'));
  1098.     s.push('<menu>'); +
  1099.     s.push('<menurow><<userPage|shortcut=u|user page>>|<<userSpace|space>></menurow>');
  1100.     s.push('<<userTalk|shortcut=t|user talk>><<editUserTalk|edit user talk>>' +
  1101.            '<<newUserTalk|shortcut=+|leave comment>>');
  1102.     if(!shorter) { s.push( 'if(ipuser){<<arin>>}else{' + email + '}') }
  1103.     else { s.push( 'if(ipuser){}else{' + email + '}') }
  1104.     s.push('<hr>' + contribs + '<<userlog|shortcut=L|user log>>');
  1105.     s.push('if(wikimedia){<<count|shortcut=#|edit counter>>}');
  1106.     s.push('if(admin){<menurow><<unblock|unblockShort>>|<<block|shortcut=b|block user>></menurow>}');
  1107.     s.push('<<blocklog|shortcut=B|block log>>' + getValueOf('popupExtraUserMenu'));
  1108.     s.push('</menu>'  + enddiv + '}');
  1109.  
  1110.     // popups menu starts here
  1111.     if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) {
  1112.         x.navpop.hasPopupMenu=true;
  1113.         s.push('*' + dropdiv + menuTitle('popupsMenu') + '<menu>');
  1114.         s.push('<<togglePreviews|toggle previews>>');
  1115.         s.push('<<purgePopups|reset>>');
  1116.         s.push('<<disablePopups|disable>>');
  1117.         s.push('</menu>'+enddiv);
  1118.     }
  1119.     s.push( enddiv +' * <b><i><font size=-5 color=#660033>' + WikiLook_Overlay._currentParser + ' </font></b></i>')
  1120.     return navlinkStringToHTML(s.join(''), x.article, x.params);
  1121. };
  1122.  
  1123. function menuTitle(s) {
  1124.     return '<a href="#" noPopup=1>' + popupString(s) + '</a>';
  1125. }
  1126.  
  1127. pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle;
  1128. pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks;
  1129.  
  1130. copyStructure('menus', 'shortmenus');
  1131. pg.structures.shortmenus.popupTopLinks=function(x) {
  1132.     return pg.structures.menus.popupTopLinks(x,true);
  1133. };
  1134. pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks;
  1135.  
  1136. copyStructure('shortmenus', 'dabshortmenus');
  1137. pg.structures.dabshortmenus.popupLayout=function () {
  1138.     return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks',
  1139.         'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'],
  1140.         'popupData', 'popupMiscTools', ['popupRedlink'], 'popupFixDab',
  1141.         'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview'];
  1142. };
  1143.  
  1144. copyStructure('menus', 'dabmenus');
  1145. pg.structures.dabmenus.popupLayout=pg.structures.dabshortmenus.popupLayout;
  1146.  
  1147.  
  1148. //</NOLITE>
  1149. pg.structures.lite={};
  1150. pg.structures.lite.popupLayout=function () {
  1151.     return ['popupTitle', 'popupPreview' ];
  1152. };
  1153. pg.structures.lite.popupTitle=function (x) {
  1154.     log (x.article + ': structures.lite.popupTitle');
  1155.     //return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params);
  1156.     return '<div><span class="popup_mainlink"><b>' + x.article.toString() + '</b></span></div>';
  1157. };
  1158. // ENDFILE: structures.js
  1159. // STARTFILE: autoedit.js
  1160. //<NOLITE>
  1161. function getParamValue(paramName, h) {
  1162.     if (typeof h == 'undefined' ) { h = document.location.href; }
  1163.     var cmdRe=RegExp('[&?]'+paramName+'=([^&]*)');
  1164.     var m=cmdRe.exec(h);
  1165.     if (m) {
  1166.         try {
  1167.             return decodeURIComponent(m[1]);
  1168.         } catch (someError) {}
  1169.     }
  1170.     return null;
  1171. }
  1172.  
  1173. function substitute(data,cmdBody) {
  1174.     // alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);
  1175.     var fromRe=RegExp(cmdBody.from, cmdBody.flags);
  1176.     return data.replace(fromRe, cmdBody.to);
  1177. }
  1178.  
  1179. function execCmds(data, cmdList) {
  1180.     for (var i=0; i<cmdList.length; ++i) {
  1181.         data=cmdList[i].action(data, cmdList[i]);
  1182.     }
  1183.     return data;
  1184. }
  1185.  
  1186. function parseCmd(str) {
  1187.     // returns a list of commands
  1188.     if (!str.length) { return []; }
  1189.     var p=false;
  1190.     switch (str.charAt(0)) {
  1191.     case 's':
  1192.         p=parseSubstitute(str);
  1193.         break;
  1194.     default:
  1195.         return false;
  1196.     }
  1197.     if (p) { return [p].concat(parseCmd(p.remainder)); }
  1198.     return false;
  1199. }
  1200.  
  1201. function unEscape(str, sep) {
  1202.     return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');
  1203. }
  1204.  
  1205.  
  1206. function parseSubstitute(str) {
  1207.     // takes a string like s/a/b/flags;othercmds and parses it
  1208.  
  1209.     var from,to,flags,tmp;
  1210.  
  1211.     if (str.length<4) { return false; }
  1212.     var sep=str.charAt(1);
  1213.     str=str.substring(2);
  1214.  
  1215.     tmp=skipOver(str,sep);
  1216.     if (tmp) { from=tmp.segment; str=tmp.remainder; }
  1217.     else { return false; }
  1218.  
  1219.     tmp=skipOver(str,sep);
  1220.     if (tmp) { to=tmp.segment; str=tmp.remainder; }
  1221.     else { return false; }
  1222.  
  1223.     flags='';
  1224.     if (str.length) {
  1225.         tmp=skipOver(str,';') || skipToEnd(str, ';');
  1226.         if (tmp) {flags=tmp.segment; str=tmp.remainder; }
  1227.     }
  1228.  
  1229.     return {action: substitute, from: from, to: to, flags: flags, remainder: str};
  1230.  
  1231. }
  1232.  
  1233. function skipOver(str,sep) {
  1234.     var endSegment=findNext(str,sep);
  1235.     if (endSegment<0) { return false; }
  1236.     var segment=unEscape(str.substring(0,endSegment), sep);
  1237.     return {segment: segment, remainder: str.substring(endSegment+1)};
  1238. }
  1239.  
  1240. function skipToEnd(str,sep) {
  1241.     return {segment: str, remainder: ''};
  1242. }
  1243.  
  1244. function findNext(str, ch) {
  1245.     for (var i=0; i<str.length; ++i) {
  1246.         if (str.charAt(i)=='\\') { i+=2; }
  1247.         if (str.charAt(i)==ch) { return i; }
  1248.     }
  1249.     return -1;
  1250. }
  1251.  
  1252. function setCheckbox(param, box) {
  1253.     var val=getParamValue(param);
  1254.     if (val!==null) {
  1255.         switch (val) {
  1256.         case '1': case 'yes': case 'true':
  1257.             box.checked=true;
  1258.             break;
  1259.         case '0': case 'no':  case 'false':
  1260.             box.checked=false;
  1261.         }
  1262.     }
  1263. }
  1264.  
  1265. function autoEdit() {
  1266.     if (!setupPopups.completed) { setupPopups(); }
  1267.     if (!document.editform || !window.wgEnableAPI || !wgEnableAPI ) { return false; }
  1268.     if (window.autoEdit.alreadyRan) { return false; }
  1269.     window.autoEdit.alreadyRan=true;
  1270.     var cmdString=getParamValue('autoedit');
  1271.     if (cmdString) {
  1272.         try {
  1273.             var editbox=document.editform.wpTextbox1;
  1274.         } catch (dang) { return; }
  1275.         var cmdList=parseCmd(cmdString);
  1276.         var input=editbox.value;
  1277.         var output=execCmds(input, cmdList);
  1278.         editbox.value=output;
  1279.         // wikEd user script compatibility
  1280.         if (typeof(wikEdUseWikEd) != 'undefined') {
  1281.             if (wikEdUseWikEd == true) {
  1282.                 WikEdUpdateFrame();
  1283.             }
  1284.         }
  1285.     }
  1286.     setCheckbox('autominor', document.editform.wpMinoredit);
  1287.     setCheckbox('autowatch', document.editform.wpWatchthis);
  1288.  
  1289.     var rvid = getParamValue('autorv');
  1290.     if (rvid) {
  1291.         var url=pg.wiki.wikibase + '/api.php?action=query&format=json&prop=revisions&revids='+rvid;
  1292.         startDownload(url, null, autoEdit2);
  1293.     } else { autoEdit2(); }
  1294. }
  1295.  
  1296. function autoEdit2(d) {
  1297.     var summary=getParamValue('autosummary');
  1298.     var summaryprompt=getParamValue('autosummaryprompt');
  1299.     var summarynotice='';
  1300.     if (d && d.data && getParamValue('autorv')) {
  1301.         var s = getRvSummary(summary, d.data);
  1302.         if (s===false) {
  1303.             summaryprompt=true;
  1304.             summarynotice=popupString('Failed to get revision information, please edit manually.\n\n');
  1305.             summary = simplePrintf(summary, [getParamValue('autorv'), '(unknown)', '(unknown)']);
  1306.         } else { summary = s; }
  1307.     }
  1308.     if (summaryprompt) {
  1309.         var txt= summarynotice +
  1310.             popupString('Enter a non-empty edit summary or press cancel to abort');
  1311.         var response=prompt(txt, summary);
  1312.         if (response) { summary=response; }
  1313.         else { return; }
  1314.     }
  1315.     if (summary) { document.editform.wpSummary.value=summary; }
  1316.     // Attempt to avoid possible premature clicking of the save button
  1317.     // (maybe delays in updates to the DOM are to blame?? or a red herring)
  1318.     setTimeout(autoEdit3, 100);
  1319. }
  1320.  
  1321. function autoClickToken() {
  1322.     return document.cookie.substr(document.cookie.indexOf("session=")+8,4);
  1323. }
  1324.  
  1325. function autoEdit3() {
  1326.     if( getParamValue('actoken') != autoClickToken()) return;
  1327.  
  1328.     var btn=getParamValue('autoclick');
  1329.     if (btn) {
  1330.         if (document.editform && document.editform[btn]) {
  1331.             var button=document.editform[btn];
  1332.             var msg=tprintf('The %s button has been automatically clicked. Please wait for the next page to load.',
  1333.                     [ button.value ]);
  1334.             bannerMessage(msg);
  1335.             document.title='('+document.title+')';
  1336.             button.click();
  1337.         } else {
  1338.             alert(tprintf('Could not find button %s. Please check the settings in your javascript file.',
  1339.                       [ btn ]));
  1340.         }
  1341.     }
  1342. }
  1343.  
  1344. function bannerMessage(s) {
  1345.     var headings=document.getElementsByTagName('h1');
  1346.     if (headings) {
  1347.         var div=document.createElementNS("http://www.w3.org/1999/xhtml",'div');
  1348.         div.innerHTML='<font size=+1><b>' + s + '</b></font>';
  1349.         headings[0].parentNode.insertBefore(div, headings[0]);
  1350.     }
  1351. }
  1352.  
  1353. function getRvSummary(template, json) {
  1354.     try {
  1355.         var o=getJsObj(json);
  1356.         var edit = anyChild(o.query.pages).revisions[0];
  1357.     } catch (badness) {return false;}
  1358.     var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, '');
  1359.     return simplePrintf(template, [edit.revid, timestamp, edit.user]);
  1360. }
  1361.  
  1362. //</NOLITE>
  1363. // ENDFILE: autoedit.js
  1364. // STARTFILE: downloader.js
  1365. /**
  1366.    @fileoverview
  1367.    {@link Downloader}, a xmlhttprequest wrapper, and helper functions.
  1368. */
  1369.  
  1370. /**
  1371.    Creates a new Downloader
  1372.    @constructor
  1373.    @class The Downloader class. Create a new instance of this class to download stuff.
  1374.    @param {String} url The url to download. This can be omitted and supplied later.
  1375. */
  1376. function Downloader(url) {
  1377.     // Source: http://jibbering.com/2002/4/httprequest.html
  1378.     /** xmlhttprequest object which we're wrapping */
  1379.     this.http = false;
  1380.  
  1381.     /*@cc_on @*/
  1382.     /*@if (@_jscript_version >= 5)
  1383.     // JScript gives us Conditional compilation,
  1384.     // we can cope with old IE versions.
  1385.     // and security blocked creation of the objects.
  1386.     try {
  1387.     this.http = new ActiveXObject("Msxml2.XMLHTTP");
  1388.     } catch (e) {
  1389.     try {
  1390.     this.http = new ActiveXObject("Microsoft.XMLHTTP");
  1391.     } catch (E) {
  1392.     // this.http = false;
  1393.     }
  1394.     }
  1395.     @end @*/
  1396.  
  1397.     if (! this.http && typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); }
  1398.     /**
  1399.         The url to download
  1400.         @type String
  1401.     */
  1402.     this.url = url;
  1403.     /**
  1404.         A universally unique ID number
  1405.         @type integer
  1406.     */
  1407.     this.id=null;
  1408.     /**
  1409.         Modification date, to be culled from the incoming headers
  1410.         @type Date
  1411.         @private
  1412.     */
  1413.     this.lastModified = null;
  1414.     /**
  1415.         What to do when the download completes successfully
  1416.         @type Function
  1417.         @private
  1418.     */
  1419.     this.callbackFunction = null;
  1420.     /**
  1421.         What to do on failure
  1422.         @type Function
  1423.         @private
  1424.     */
  1425.     this.onFailure = null;
  1426.     /**
  1427.         Flag set on <code>abort</code>
  1428.         @type boolean
  1429.     */
  1430.     this.aborted = false;
  1431.     /**
  1432.        HTTP method. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities.
  1433.        @type String
  1434.     */
  1435.     this.method='GET';
  1436.     /**
  1437.         Async flag.
  1438.         @type boolean
  1439.     */
  1440.     this.async=true;
  1441. }
  1442.  
  1443. new Downloader();
  1444.  
  1445. /** Submits the http request. */
  1446. Downloader.prototype.send = function (x) {
  1447.     if (!this.http) { return null; }
  1448.     return this.http.send(x);
  1449. };
  1450. /** Aborts the download, setting the <code>aborted</code> field to true.  */
  1451. Downloader.prototype.abort = function () {
  1452.     if (!this.http) { return null; }
  1453.     this.aborted=true;
  1454.     return this.http.abort();
  1455. };
  1456. /** Returns the downloaded data. */
  1457. Downloader.prototype.getData = function () {if (!this.http) { return null; } return this.http.responseText;};
  1458. /** Prepares the download. */
  1459. Downloader.prototype.setTarget = function () {
  1460.     if (!this.http) { return null; }
  1461.     this.http.open(this.method, this.url, this.async);
  1462. };
  1463. /** Gets the state of the download. */
  1464. Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;};
  1465.  
  1466. pg.misc.downloadsInProgress = { };
  1467.  
  1468. /** Starts the download.
  1469.     Note that setTarget {@link Downloader#setTarget} must be run first
  1470. */
  1471. Downloader.prototype.start=function () {
  1472.     if (!this.http) { return; }
  1473.     pg.misc.downloadsInProgress[this.id] = this;
  1474.     this.http.send(null);
  1475. };
  1476.  
  1477. /** Gets the 'Last-Modified' date from the download headers.
  1478.     Should be run after the download completes.
  1479.     Returns <code>null</code> on failure.
  1480.     @return {Date}
  1481. */
  1482. Downloader.prototype.getLastModifiedDate=function () {
  1483.     if(!this.http) { return null; }
  1484.     var lastmod=null;
  1485.     try {
  1486.         lastmod=this.http.getResponseHeader('Last-Modified');
  1487.     } catch (err) {}
  1488.     if (lastmod) { return new Date(lastmod); }
  1489.     return null;
  1490. };
  1491.  
  1492. /** Sets the callback function.
  1493.     @param {Function} f callback function, called as <code>f(this)</code> on success
  1494. */
  1495. Downloader.prototype.setCallback = function (f) {
  1496.     if(!this.http) { return; }
  1497.     this.http.onreadystatechange = f;
  1498. };
  1499.  
  1500. Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; };
  1501.  
  1502. //////////////////////////////////////////////////
  1503. // helper functions
  1504.  
  1505. /** Creates a new {@link Downloader} and prepares it for action.
  1506.     @param {String} url The url to download
  1507.     @param {integer} id The ID of the {@link Downloader} object
  1508.     @param {Function} callback The callback function invoked on success
  1509.     @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser
  1510. */
  1511. function newDownload(url, id, callback, onfailure) {
  1512.     var d=new Downloader(url);
  1513.     if (!d.http) { return 'ohdear'; }
  1514.     d.id=id;
  1515.     d.setTarget();
  1516.     if (!onfailure) {
  1517.         onfailure=2;
  1518.     }
  1519.     var f = function () {
  1520.         if (d.getReadyState() == 4) {
  1521.             delete pg.misc.downloadsInProgress[this.id];
  1522.             try {
  1523.                 if ( d.getStatus() == 200 ) {
  1524.                     d.data=d.getData();
  1525.                     d.lastModified=d.getLastModifiedDate();
  1526.                     callback(d);
  1527.                 } else if (typeof onfailure == typeof 1) {
  1528.                     if (onfailure > 0) {
  1529.                         // retry
  1530.                         newDownload(url, id, callback, onfailure - 1);
  1531.                     }
  1532.                 } else if (typeof onfailure == 'function') {
  1533.                     onfailure(d,url,id,callback);
  1534.                 }
  1535.             } catch (somerr) { /* ignore it */ }
  1536.         }
  1537.     };
  1538.     d.setCallback(f);
  1539.     return d;
  1540. }
  1541. /** Simulates a download from cached data.
  1542.     The supplied data is put into a {@link Downloader} as if it had downloaded it.
  1543.     @param {String} url The url.
  1544.     @param {integer} id The ID.
  1545.     @param {Function} callback The callback, which is invoked immediately as <code>callback(d)</code>,
  1546.     where <code>d</code> is the new {@link Downloader}.
  1547.     @param {String} data The (cached) data.
  1548.     @param {Date} lastModified The (cached) last modified date.
  1549. */
  1550. function fakeDownload(url, id, callback, data, lastModified, owner) {
  1551.     var d=newDownload(url,callback);
  1552.     d.owner=owner;
  1553.     d.id=id; d.data=data;
  1554.     d.lastModified=lastModified;
  1555.     return callback(d);
  1556. }
  1557.  
  1558. /**
  1559.    Starts a download.
  1560.    @param {String} url The url to download
  1561.    @param {integer} id The ID of the {@link Downloader} object
  1562.    @param {Function} callback The callback function invoked on success
  1563.    @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser
  1564. */
  1565. function startDownload(url, id, callback) {
  1566.     var d=newDownload(url, id, callback);
  1567.     if (typeof d == typeof '' ) { return d; }
  1568.     d.start();
  1569.     return d;
  1570. }
  1571.  
  1572. /**
  1573.    Aborts all downloads which have been started.
  1574. */
  1575. function abortAllDownloads() {
  1576.     for ( var x in pg.misc.downloadsInProgress ) {
  1577.         try {
  1578.             pg.misc.downloadsInProgress[x].aborted=true;
  1579.             pg.misc.downloadsInProgress[x].abort();
  1580.             delete pg.misc.downloadsInProgress[x];
  1581.         } catch (e) { }
  1582.     }
  1583. }
  1584. // ENDFILE: downloader.js
  1585. // STARTFILE: livepreview.js
  1586. // TODO: location is often not correct (eg relative links in previews)
  1587.  
  1588. /**
  1589.  * InstaView - a Mediawiki to HTML converter in JavaScript
  1590.  * Version 0.6.1
  1591.  * Copyright (C) Pedro Fayolle 2005-2006
  1592.  * http://en.wikipedia.org/wiki/User:Pilaf
  1593.  * Distributed under the BSD license
  1594.  *
  1595.  * Changelog:
  1596.  *
  1597.  * 0.6.1
  1598.  * - Fixed problem caused by \r characters
  1599.  * - Improved inline formatting parser
  1600.  *
  1601.  * 0.6
  1602.  * - Changed name to InstaView
  1603.  * - Some major code reorganizations and factored out some common functions
  1604.  * - Handled conversion of relative links (i.e. [[/foo]])
  1605.  * - Fixed misrendering of adjacent definition list items
  1606.  * - Fixed bug in table headings handling
  1607.  * - Changed date format in signatures to reflect Mediawiki's
  1608.  * - Fixed handling of [[:Image:...]]
  1609.  * - Updated MD5 function (hopefully it will work with UTF-8)
  1610.  * - Fixed bug in handling of links inside images
  1611.  *
  1612.  * To do:
  1613.  * - Better support for <math>
  1614.  * - Full support for <nowiki>
  1615.  * - Parser-based (as opposed to RegExp-based) inline wikicode handling (make it one-pass and bullet-proof)
  1616.  * - Support for templates (through AJAX)
  1617.  * - Support for coloured links (AJAX)
  1618.  */
  1619.  
  1620.  
  1621. var Insta = {}
  1622.  
  1623. function setupLivePreview() {
  1624.  
  1625.     // options
  1626.     Insta.conf =
  1627.     {
  1628.         baseUrl: '',
  1629.  
  1630.         user: {},
  1631.  
  1632.         wiki: {
  1633.         lang: pg.wiki.lang,
  1634.         interwiki: pg.wiki.interwiki,
  1635.         default_thumb_width: 180
  1636.         },
  1637.  
  1638.         paths: {
  1639.         articles: '/' + joinPath([pg.wiki.prePath, pg.wiki.articlePath]) + '/',
  1640.         math: '/math/', // FIXME
  1641.         images: ( window.getImageUrlStart ? getImageUrlStart(pg.wiki.hostname) : ''),
  1642.         images_fallback: 'http://upload.wikimedia.org/wikipedia/commons/',
  1643.         magnify_icon: 'skins/common/images/magnify-clip.png'
  1644.         },
  1645.  
  1646.         locale: {
  1647.         user: pg.ns.user,
  1648.         image: pg.ns.image,
  1649.         category: pg.ns.category,
  1650.         // shouldn't be used in popup previews, i think
  1651.         months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  1652.         }
  1653.     }
  1654.  
  1655.     // options with default values or backreferences
  1656.     with (Insta.conf) {
  1657.     user.name = user.name || 'Wikipedian'
  1658.     user.signature = '[['+locale.user+':'+user.name+'|'+user.name+']]'
  1659.     //paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/'
  1660.     }
  1661.  
  1662.     // define constants
  1663.     Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+
  1664.                        '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');
  1665.  
  1666. }
  1667.  
  1668.  
  1669. Insta.dump = function(from, to)
  1670. {
  1671.     if (typeof from == 'string') from = content.document.getElementById(from)
  1672.     if (typeof to == 'string') to = content.document.getElementById(to)
  1673.     to.innerHTML = this.convert(from.value)
  1674. }
  1675.  
  1676. Insta.convert = function(wiki)
  1677. {
  1678.     var    ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode
  1679.         o='',    // output
  1680.         p=0,    // para flag
  1681.         $r    // result of passing a regexp to $()
  1682.  
  1683.     // some shorthands
  1684.     function remain() { return ll.length }
  1685.     function sh() { return ll.shift() } // shift
  1686.     function ps(s) { o+=s } // push
  1687.  
  1688.     function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks
  1689.     {
  1690.         var i=1,a=arguments,f=a[0],o='',c,p
  1691.         for (;i<a.length; i++) if ((p=f.indexOf('?'))+1) {
  1692.             // allow character escaping
  1693.             i -= c=f.charAt(p+1)=='?'?1:0
  1694.             o += f.substring(0,p)+(c?'?':a[i])
  1695.             f=f.substr(p+1+c)
  1696.         } else break;
  1697.         return o+f
  1698.     }
  1699.  
  1700.     function html_entities(s) { return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") }
  1701.  
  1702.     function max(a,b) { return (a>b)?a:b }
  1703.     function min(a,b) { return (a<b)?a:b }
  1704.  
  1705.     // return the first non matching character position between two strings
  1706.     function str_imatch(a, b)
  1707.     {
  1708.         for (var i=0, l=min(a.length, b.length); i<l; i++) if (a.charAt(i)!=b.charAt(i)) break
  1709.         return i
  1710.     }
  1711.  
  1712.     // compare current line against a string or regexp
  1713.     // if passed a string it will compare only the first string.length characters
  1714.     // if passed a regexp the result is stored in $r
  1715.     function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)) }
  1716.  
  1717.     function $$(c) { return ll[0]==c } // compare current line against a string
  1718.     function _(p) { return ll[0].charAt(p) } // return char at pos p
  1719.  
  1720.     function endl(s) { ps(s); sh() }
  1721.  
  1722.     function parse_list()
  1723.     {
  1724.         var prev='';
  1725.  
  1726.         while (remain() && $(/^([*#:;]+)(.*)$/)) {
  1727.  
  1728.             var l_match = $r
  1729.  
  1730.             sh()
  1731.  
  1732.             var ipos = str_imatch(prev, l_match[1])
  1733.  
  1734.             // close uncontinued lists
  1735.             for (var i=prev.length-1; i >= ipos; i--) {
  1736.  
  1737.                 var pi = prev.charAt(i)
  1738.  
  1739.                 if (pi=='*') ps('</ul>')
  1740.                 else if (pi=='#') ps('</ol>')
  1741.                 // close a dl only if the new item is not a dl item (:, ; or empty)
  1742.                 else switch (l_match[1].charAt(i)) { case'':case'*':case'#': ps('</dl>') }
  1743.             }
  1744.  
  1745.             // open new lists
  1746.             for (var i=ipos; i<l_match[1].length; i++) {
  1747.  
  1748.                 var li = l_match[1].charAt(i)
  1749.  
  1750.                 if (li=='*') ps('<ul>')
  1751.                 else if (li=='#') ps('<ol>')
  1752.                 // open a new dl only if the prev item is not a dl item (:, ; or empty)
  1753.                 else switch(prev.charAt(i)) { case'':case'*':case'#': ps('<dl>') }
  1754.             }
  1755.  
  1756.             switch (l_match[1].charAt(l_match[1].length-1)) {
  1757.  
  1758.                 case '*': case '#':
  1759.                     ps('<li>' + parse_inline_nowiki(l_match[2])); break
  1760.  
  1761.                 case ';':
  1762.                     ps('<dt>')
  1763.  
  1764.                     var dt_match
  1765.  
  1766.                     // handle ;dt :dd format
  1767.                     if (dt_match = l_match[2].match(/(.*?)(:.*?)$/)) {
  1768.  
  1769.                         ps(parse_inline_nowiki(dt_match[1]))
  1770.                         ll.unshift(dt_match[2])
  1771.  
  1772.                     } else ps(parse_inline_nowiki(l_match[2]))
  1773.  
  1774.                     break
  1775.  
  1776.                 case ':':
  1777.                     ps('<dd>' + parse_inline_nowiki(l_match[2]))
  1778.             }
  1779.  
  1780.             prev=l_match[1]
  1781.         }
  1782.  
  1783.         // close remaining lists
  1784.         for (var i=prev.length-1; i>=0; i--)
  1785.             ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl')))
  1786.     }
  1787.  
  1788.     function parse_table()
  1789.     {
  1790.         endl(f('<table?>', $(/^\{\|( .*)$/)? $r[1]: ''))
  1791.  
  1792.         for (;remain();) if ($('|')) switch (_(1)) {
  1793.             case '}': endl('</table>'); return
  1794.             case '-': endl(f('<tr ?>', $(/\|-*(.*)/)[1])); break
  1795.             default: parse_table_data()
  1796.         }
  1797.         else if ($('!')) parse_table_data()
  1798.         else sh()
  1799.     }
  1800.  
  1801.     function parse_table_data()
  1802.     {
  1803.         var td_line, match_i
  1804.  
  1805.         // 1: "|+", '|' or '+'
  1806.         // 2: ??
  1807.         // 3: attributes ??
  1808.         // TODO: finish commenting this regexp
  1809.         var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/)
  1810.  
  1811.         if (td_match[1] == '|+') ps('<caption');
  1812.         else ps('<t' + ((td_match[1]=='|')?'d':'h'))
  1813.  
  1814.         if (typeof td_match[3] != 'undefined') {
  1815.  
  1816.             ps(' ' + td_match[3])
  1817.             match_i = 4
  1818.  
  1819.         } else match_i = 2
  1820.  
  1821.         ps('>')
  1822.  
  1823.         if (td_match[1] != '|+') {
  1824.  
  1825.             // use || or !! as a cell separator depending on context
  1826.             // NOTE: when split() is passed a regexp make sure to use non-capturing brackets
  1827.             td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/)
  1828.  
  1829.             ps(parse_inline_nowiki(td_line.shift()))
  1830.  
  1831.             while (td_line.length) ll.unshift(td_match[1] + td_line.pop())
  1832.  
  1833.         } else ps(td_match[match_i])
  1834.  
  1835.         var tc = 0, td = []
  1836.  
  1837.         for (;remain(); td.push(sh()))
  1838.         if ($('|')) {
  1839.             if (!tc) break // we're at the outer-most level (no nested tables), skip to td parse
  1840.             else if (_(1)=='}') tc--
  1841.         }
  1842.         else if (!tc && $('!')) break
  1843.         else if ($('{|')) tc++
  1844.  
  1845.         if (td.length) ps(Insta.convert(td))
  1846.     }
  1847.  
  1848.     function parse_pre()
  1849.     {
  1850.         ps('<pre>')
  1851.         do endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); while (remain() && $(' '))
  1852.         ps('</pre>')
  1853.     }
  1854.  
  1855.     function parse_block_image()
  1856.     {
  1857.         ps(parse_image(sh()))
  1858.     }
  1859.  
  1860.     function parse_image(str)
  1861.     {
  1862. //<NOLITE>
  1863.         // get what's in between "[[Image:" and "]]"
  1864.         var tag = str.substring(str.indexOf(':') + 1, str.length - 2);
  1865.  
  1866.         var width;
  1867.         var attr = [], filename, caption = '';
  1868.         var thumb=0, frame=0, center=0;
  1869.         var align='';
  1870.  
  1871.         if (tag.match(/\|/)) {
  1872.             // manage nested links
  1873.             var nesting = 0;
  1874.             var last_attr;
  1875.             for (var i = tag.length-1; i > 0; i--) {
  1876.                 if (tag.charAt(i) == '|' && !nesting) {
  1877.                     last_attr = tag.substr(i+1);
  1878.                     tag = tag.substring(0, i);
  1879.                     break;
  1880.                 } else switch (tag.substr(i-1, 2)) {
  1881.                     case ']]':
  1882.                         nesting++;
  1883.                         i--;
  1884.                         break;
  1885.                     case '[[':
  1886.                         nesting--;
  1887.                         i--;
  1888.                 }
  1889.             }
  1890.  
  1891.             attr = tag.split(/\s*\|\s*/);
  1892.             attr.push(last_attr);
  1893.             filename = attr.shift();
  1894.  
  1895.             var w_match;
  1896.  
  1897.             for (;attr.length; attr.shift())
  1898.             if (w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/)) width = w_match[1]
  1899.             else switch(attr[0]) {
  1900.                 case 'thumb':
  1901.                 case 'thumbnail':
  1902.                     thumb=true;
  1903.                 case 'frame':
  1904.                     frame=true;
  1905.                     break;
  1906.                 case 'none':
  1907.                 case 'right':
  1908.                 case 'left':
  1909.                     center=false;
  1910.                     align=attr[0];
  1911.                     break;
  1912.                 case 'center':
  1913.                     center=true;
  1914.                     align='none';
  1915.                     break;
  1916.                 default:
  1917.                     if (attr.length == 1) caption = attr[0];
  1918.             }
  1919.  
  1920.         } else filename = tag;
  1921.  
  1922.  
  1923.         var o='';
  1924.  
  1925.         if (frame) {
  1926.  
  1927.             if (align=='') align = 'right';
  1928.  
  1929.             o += f("<div class='thumb t?'>", align);
  1930.  
  1931.             if (thumb) {
  1932.                 if (!width) width = Insta.conf.wiki.default_thumb_width;
  1933.  
  1934.                 o += f("<div style='width:?px;'>?", 2+width*1, make_image(filename, caption, width)) +
  1935.                     f("<div class='thumbcaption'><div class='magnify' style='float:right'><a href='?' class='internal' title='Enlarge'><img src='?'></a></div>?</div>",
  1936.                         Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename,
  1937.                         Insta.conf.paths.magnify_icon,
  1938.                         parse_inline_nowiki(caption)
  1939.                     )
  1940.             } else {
  1941.                 o += '<div>' + make_image(filename, caption) + f("<div class='thumbcaption'>?</div>", parse_inline_nowiki(caption))
  1942.             }
  1943.  
  1944.             o += '</div></div>';
  1945.  
  1946.         } else if (align != '') {
  1947.             o += f("<div class='float?'><span>?</span></div>", align, make_image(filename, caption, width));
  1948.         } else {
  1949.             return make_image(filename, caption, width);
  1950.         }
  1951.  
  1952.         return center? f("<div class='center'>?</div>", o): o;
  1953. //</NOLITE>
  1954.     }
  1955.  
  1956.     function parse_inline_nowiki(str)
  1957.     {
  1958.         var start, lastend=0
  1959.         var substart=0, nestlev=0, open, close, subloop;
  1960.         var html='';
  1961.  
  1962.         while (-1 != (start = str.indexOf('<nowiki>', substart))) {
  1963.             html += parse_inline_wiki(str.substring(lastend, start));
  1964.             start += 8;
  1965.             substart = start;
  1966.             subloop = true;
  1967.             do {
  1968.                 open = str.indexOf('<nowiki>', substart);
  1969.                 close = str.indexOf('</nowiki>', substart);
  1970.                 if (close<=open || open==-1) {
  1971.                     if (close==-1) {
  1972.                         return html + html_entities(str.substr(start));
  1973.                     }
  1974.                     substart = close+9;
  1975.                     if (nestlev) {
  1976.                         nestlev--;
  1977.                     } else {
  1978.                         lastend = substart;
  1979.                         html += html_entities(str.substring(start, lastend-9));
  1980.                         subloop = false;
  1981.                     }
  1982.                 } else {
  1983.                     substart = open+8;
  1984.                     nestlev++;
  1985.                 }
  1986.             } while (subloop)
  1987.         }
  1988.  
  1989.         return html + parse_inline_wiki(str.substr(lastend));
  1990.     }
  1991.  
  1992.     function make_image(filename, caption, width)
  1993.     {
  1994. //<NOLITE>
  1995.         // uppercase first letter in file name
  1996.         filename = filename.charAt(0).toUpperCase() + filename.substr(1);
  1997.         // replace spaces with underscores
  1998.         filename = filename.replace(/ /g, '_');
  1999.  
  2000.         caption = strip_inline_wiki(caption);
  2001.  
  2002.         var md5 = hex_md5(filename);
  2003.  
  2004.         var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename;
  2005.  
  2006.         if (width) width = "width='" + width + "px'";
  2007.  
  2008.         var img = f("<img onerror=\"this.onerror=null;this.src='?'\" src='?' ? ?>", Insta.conf.paths.images_fallback + source, Insta.conf.paths.images + source, (caption!='')? "alt='" + caption + "'" : '', width);
  2009.  
  2010.         return f("<a class='image' ? href='?'>?</a>", (caption!='')? "title='" + caption + "'" : '', Insta.conf.paths.articles + Insta.conf.locale.image + ':' + filename, img);
  2011. //</NOLITE>
  2012.     }
  2013.  
  2014.     function parse_inline_images(str)
  2015.     {
  2016. //<NOLITE>
  2017.         var start, substart=0, nestlev=0;
  2018.         var loop, close, open, wiki, html;
  2019.  
  2020.         while (-1 != (start=str.indexOf('[[', substart))) {
  2021.             if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) {
  2022.                 loop=true;
  2023.                 substart=start;
  2024.                 do {
  2025.                     substart+=2;
  2026.                     close=str.indexOf(']]',substart);
  2027.                     open=str.indexOf('[[',substart);
  2028.                     if (close<=open||open==-1) {
  2029.                         if (close==-1) return str;
  2030.                         substart=close;
  2031.                         if (nestlev) {
  2032.                             nestlev--;
  2033.                         } else {
  2034.                             wiki=str.substring(start,close+2);
  2035.                             html=parse_image(wiki);
  2036.                             str=str.replace(wiki,html);
  2037.                             substart=start+html.length;
  2038.                             loop=false;
  2039.                         }
  2040.                     } else {
  2041.                         substart=open;
  2042.                         nestlev++;
  2043.                     }
  2044.                 } while (loop)
  2045.  
  2046.             } else break;
  2047.         }
  2048.  
  2049. //</NOLITE>
  2050.         return str;
  2051.     }
  2052.  
  2053.     // the output of this function doesn't respect the FILO structure of HTML
  2054.     // but since most browsers can handle it I'll save myself the hassle
  2055.     function parse_inline_formatting(str)
  2056.     {
  2057.         var em,st,i,li,o='';
  2058.         while ((i=str.indexOf("''",li))+1) {
  2059.             o += str.substring(li,i);
  2060.             li=i+2;
  2061.             if (str.charAt(i+2)=="'") {
  2062.                 li++;
  2063.                 st=!st;
  2064.                 o+=st?'<strongWikiLook>':'</strongWikiLook>';
  2065.             } else {
  2066.                 em=!em;
  2067.                 o+=em?'<emWikiLook>':'</emWikiLook>';
  2068.             }
  2069.         }
  2070.         return o+str.substr(li);
  2071.     }
  2072.  
  2073.     function parse_inline_wiki(str)
  2074.     {
  2075.         var aux_match;
  2076.  
  2077.         str = parse_inline_images(str);
  2078.         str = parse_inline_formatting(str);
  2079.  
  2080.         // math
  2081.         while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) {
  2082.             var math_md5 = hex_md5(aux_match[1]);
  2083.             str = str.replace(aux_match[0], f("<img src='?.png'>", Insta.conf.paths.math+math_md5));
  2084.         }
  2085.  
  2086.         // Build a Mediawiki-formatted date string
  2087.         var date = new Date;
  2088.         var minutes = date.getUTCMinutes();
  2089.         if (minutes < 10) minutes = '0' + minutes;
  2090.         var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear());
  2091.  
  2092.         // text formatting
  2093.         return str.
  2094.             // signatures
  2095.             replace(/~{5}(?!~)/g, date).
  2096.             replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date).
  2097.             replace(/~{3}(?!~)/g, Insta.conf.user.name).
  2098.  
  2099.             // [[:Category:...]], [[:Image:...]], etc...
  2100.             replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$1$2</a>").
  2101.             // remove straight category and interwiki tags
  2102.             replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),'').
  2103.  
  2104.             // [[:Category:...|Links]], [[:Image:...|Links]], etc...
  2105.             replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), "<a href='"+Insta.conf.paths.articles+"$1'>$2$3</a>").
  2106.  
  2107.             // [[/Relative links]]
  2108.             replace(/\[\[(\/[^|]*?)\]\]/g, f("<a href='?$1'>$1</a>", Insta.conf.baseUrl)).
  2109.  
  2110.             // [[/Replaced|Relative links]]
  2111.             replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f("<a href='?$1'>$2</a>", Insta.conf.baseUrl)).
  2112.  
  2113.             // [[Common links]]
  2114.             replace(/\[\[([^|]*?)\]\](\w*)/g, f("<a href='?$1'>$1$2</a>", Insta.conf.paths.articles)).
  2115.  
  2116.             // [[Replaced|Links]]
  2117.             replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, f("<a href='?$1'>$2$3</a>", Insta.conf.paths.articles)).
  2118.  
  2119.             // [[Stripped:Namespace|Namespace]]
  2120.             replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f("<a href='?$1$2$3'>$2</a>", Insta.conf.paths.articles)).
  2121.  
  2122.             // External links
  2123.             replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "<a class='external' href='$1:$2$3'>$4</a>").
  2124.             replace(/\[http:\/\/(.*?)\]/g, "<a class='external' href='http://$1'>[#]</a>").
  2125.             replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "<a class='external' href='$1:$2$3'>$1:$2$3</a>").
  2126.             replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, "$1<a class='external' href='$2:$3$4'>$2:$3$4</a>").
  2127.  
  2128.             replace('__NOTOC__','').
  2129.             replace('__NOEDITSECTION__','');
  2130.     }
  2131. /*
  2132. */
  2133.     function strip_inline_wiki(str)
  2134.     {
  2135.         return str
  2136.             .replace(/\[\[[^\]]*\|(.*?)\]\]/g,'$1')
  2137.             .replace(/\[\[(.*?)\]\]/g,'$1')
  2138.             .replace(/''(.*?)''/g,'$1');
  2139.     }
  2140.  
  2141.     // begin parsing
  2142.     for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) {
  2143.         p=0
  2144.         endl(f('<WikiLookh?>?</WikiLookh?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3]))
  2145.  
  2146.     } else if ($(/^[*#:;]/)) {
  2147.         p=0
  2148.         parse_list()
  2149.  
  2150.     } else if ($(' ')) {
  2151.         p=0
  2152.         parse_pre()
  2153.  
  2154.     } else if ($('{|')) {
  2155.         p=0
  2156.         parse_table()
  2157.  
  2158.     } else if ($(/^----+$/)) {
  2159.         p=0
  2160.         endl('<hr>')
  2161.  
  2162.     } else if ($(Insta.BLOCK_IMAGE)) {
  2163.         p=0
  2164.         parse_block_image()
  2165.  
  2166.     } else {
  2167.  
  2168.         // handle paragraphs
  2169.         if ($$('')) {
  2170.             if (p = (remain()>1 && ll[1]==(''))) endl('<p><br>')
  2171.         } else {
  2172.             if(!p) {
  2173.                 ps('<p>')
  2174.                 p=1
  2175.             }
  2176.             ps(parse_inline_nowiki(ll[0]) + ' ')
  2177.         }
  2178.  
  2179.         sh();
  2180.     }
  2181.  
  2182.     return o
  2183. };
  2184.  
  2185. window.wiki2html=function(txt,baseurl) {
  2186.     Insta.conf.baseUrl=baseurl;
  2187.     return Insta.convert(txt);
  2188. };
  2189. // ENDFILE: livepreview.js
  2190. // STARTFILE: pageinfo.js
  2191. //<NOLITE>
  2192. function popupFilterPageSize(data) {
  2193.     return formatBytes(data.length);
  2194. }
  2195.  
  2196. function popupFilterCountLinks(data) {
  2197.     var num=countLinks(data);
  2198.     return String(num) + ' ' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
  2199. }
  2200.  
  2201. function popupFilterCountImages(data) {
  2202.     var num=countImages(data);
  2203.     return String(num) + ' ' + ((num!=1)?popupString('images'):popupString('image'));
  2204. }
  2205.  
  2206. function popupFilterCountCategories(data) {
  2207.     var num=countCategories(data);
  2208.     return String(num) + ' ' + ((num!=1)?popupString('categories'):popupString('category'));
  2209. }
  2210.  
  2211.  
  2212. function popupFilterLastModified(data,download) {
  2213.     var lastmod=download.lastModified;
  2214.     var now=new Date();
  2215.     var age=now-lastmod;
  2216.     if (lastmod && getValueOf('popupLastModified')) {
  2217.         return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), ' ');
  2218.     }
  2219.     return '';
  2220. }
  2221.  
  2222. function formatAge(age) {
  2223.     // coerce into a number
  2224.     var a=0+age, aa=a;
  2225.  
  2226.     var seclen  = 1000;
  2227.     var minlen  = 60*seclen;
  2228.     var hourlen = 60*minlen;
  2229.     var daylen  = 24*hourlen;
  2230.     var weeklen = 7*daylen;
  2231.  
  2232.     var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week');
  2233.     var numdays  = (a-a%daylen)/daylen;   a = a-numdays*daylen;   var sdays  = addunit(numdays, 'day');
  2234.     var numhours = (a-a%hourlen)/hourlen; a = a-numhours*hourlen; var shours = addunit(numhours,'hour');
  2235.     var nummins  = (a-a%minlen)/minlen;   a = a-nummins*minlen;   var smins  = addunit(nummins, 'minute');
  2236.     var numsecs  = (a-a%seclen)/seclen;   a = a-numsecs*seclen;   var ssecs  = addunit(numsecs, 'second');
  2237.  
  2238.     if (aa > 4*weeklen) { return sweeks; }
  2239.     if (aa > weeklen)   { return sweeks + ' ' + sdays; }
  2240.     if (aa > daylen)    { return sdays  + ' ' + shours; }
  2241.     if (aa > 6*hourlen) { return shours; }
  2242.     if (aa > hourlen)   { return shours + ' ' + smins; }
  2243.     if (aa > 10*minlen) { return smins; }
  2244.     if (aa > minlen)    { return smins  + ' ' + ssecs; }
  2245.     return ssecs;
  2246. }
  2247.  
  2248. function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}
  2249.  
  2250. function runPopupFilters(list, data, download) {
  2251.     var ret=[];
  2252.     for (var i=0; i<list.length; ++i) {
  2253.         if (list[i] && typeof list[i] == 'function') {
  2254.             var s=list[i](data, download, download.owner.article);
  2255.             if (s) { ret.push(s); }
  2256.         }
  2257.     }
  2258.     return ret;
  2259. }
  2260.  
  2261. function getPageInfo(data, download) {
  2262.     if (!data || data.length === 0) { return popupString('Empty page'); }
  2263.  
  2264.     var popupFilters=getValueOf('popupFilters') || [];
  2265.     var extraPopupFilters = getValueOf('extraPopupFilters') || [];
  2266.     var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download);
  2267.  
  2268.     var pageInfo=pageInfoArray.join(', ');
  2269.     if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); }
  2270.     return pageInfo;
  2271. }
  2272.  
  2273.  
  2274. // this could be improved!
  2275. function countLinks(wikiText) { return wikiText.split('[[').length - 1; }
  2276.  
  2277. // if N = # matches, n = # brackets, then
  2278. // String.parenSplit(regex) intersperses the N+1 split elements
  2279. // with Nn other elements. So total length is
  2280. // L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).
  2281.  
  2282. function countImages(wikiText) {
  2283.     return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1);
  2284. }
  2285.  
  2286. function countCategories(wikiText) {
  2287.     return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1);
  2288. }
  2289.  
  2290. function popupFilterStubDetect(data, download, article)     {
  2291.     var counts=stubCount(data, article);
  2292.     if (counts.real) { return popupString('stub'); }
  2293.     if (counts.sect) { return popupString('section stub'); }
  2294.     return '';
  2295. }
  2296.  
  2297. function popupFilterDisambigDetect(data, download, article) {
  2298.     if (getValueOf('popupOnlyArticleDabStub') && article.namespace()) { return ''; }
  2299.     return (isDisambig(data, article)) ? popupString('disambig') : '';
  2300. }
  2301.  
  2302. function formatBytes(num) {
  2303.     return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +' ' + popupString('bytes')) ;
  2304. }
  2305. //</NOLITE>
  2306. // ENDFILE: pageinfo.js
  2307. // STARTFILE: titles.js
  2308. /**
  2309.    @fileoverview Defines the {@link Title} class, and associated crufty functions.
  2310.  
  2311.    <code>Title</code> deals with article titles and their various
  2312.    forms.  {@link Stringwrapper} is the parent class of
  2313.    <code>Title</code>, which exists simply to make things a little
  2314.    neater.
  2315.  
  2316. */
  2317.  
  2318. /**
  2319.    Creates a new Stringwrapper.
  2320.    @constructor
  2321.  
  2322.    @class the Stringwrapper class. This base class is not really
  2323.    useful on its own; it just wraps various common string operations.
  2324. */
  2325. function Stringwrapper() {
  2326.     /**
  2327.        Wrapper for this.toString().indexOf()
  2328.        @param {String} x
  2329.        @type integer
  2330.     */
  2331.     this.indexOf=function(x){return this.toString().indexOf(x);};
  2332.     /**
  2333.        Returns this.value.
  2334.        @type String
  2335.     */
  2336.     this.toString=function(){return this.value;};
  2337.     /**
  2338.        Wrapper for {@link String#parenSplit} applied to this.toString()
  2339.        @param {RegExp} x
  2340.        @type Array
  2341.     */
  2342.     this.parenSplit=function(x){return this.toString().parenSplit(x);};
  2343.     /**
  2344.        Wrapper for this.toString().substring()
  2345.        @param {String} x
  2346.        @param {String} y (optional)
  2347.        @type String
  2348.     */
  2349.     this.substring=function(x,y){
  2350.         if (typeof y=='undefined') { return this.toString().substring(x); }
  2351.         return this.toString().substring(x,y);
  2352.     };
  2353.     /**
  2354.        Wrapper for this.toString().split()
  2355.        @param {String} x
  2356.        @type Array
  2357.     */
  2358.     this.split=function(x){return this.toString().split(x);};
  2359.     /**
  2360.        Wrapper for this.toString().replace()
  2361.        @param {String} x
  2362.        @param {String} y
  2363.        @type String
  2364.     */
  2365.     this.replace=function(x,y){ return this.toString().replace(x,y); };
  2366. }
  2367.  
  2368.  
  2369. /**
  2370.    Creates a new <code>Title</code>.
  2371.    @constructor
  2372.  
  2373.    @class The Title class. Holds article titles and converts them into
  2374.    various forms. Also deals with anchors, by which we mean the bits
  2375.    of the article URL after a # character, representing locations
  2376.    within an article.
  2377.  
  2378.    @param {String} value The initial value to assign to the
  2379.    article. This must be the canonical title (see {@link
  2380.    Title#value}. Omit this in the constructor and use another function
  2381.    to set the title if this is unavailable.
  2382. */
  2383. function Title(val) {
  2384.     /**
  2385.        The canonical article title. This must be in UTF-8 with no
  2386.        entities, escaping or nasties. Also, underscores should be
  2387.        replaced with spaces.
  2388.        @type String
  2389.        @private
  2390.     */
  2391.     this.value=null;
  2392.     /**
  2393.        The canonical form of the anchor. This should be exactly as
  2394.        it appears in the URL, i.e. with the .C3.0A bits in.
  2395.        @type String
  2396.     */
  2397.     this.anchor='';
  2398.  
  2399.     this.setUtf(val);
  2400. }
  2401. Title.prototype=new Stringwrapper();
  2402. /**
  2403.    Returns the canonical representation of the article title, optionally without anchor.
  2404.    @param {boolean} omitAnchor
  2405.    @fixme Decide specs for anchor
  2406.    @return String The article title and the anchor.
  2407. */
  2408. Title.prototype.toString=function(omitAnchor) {
  2409.     return this.value + ( (!omitAnchor && this.anchor) ? '#' + this.anchorString() : '' );
  2410. };
  2411. Title.prototype.anchorString=function() {
  2412.     if (!this.anchor) { return ''; }
  2413.     var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/);
  2414.     var len=split.length;
  2415.     for (var j=1; j<len; j+=2) {
  2416.         // FIXME s/decodeURI/decodeURIComponent/g ?
  2417.         split[j]=decodeURIComponent(split[j].split('.').join('%')).split('_').join(' ');
  2418.     }
  2419.     return split.join('');
  2420. };
  2421. Title.prototype.urlAnchor=function() {
  2422.     var split=this.anchor.parenSplit('/((?:[%][0-9A-F]{2})+)/');
  2423.     var len=split.length;
  2424.     for (var j=1; j<len; j+=2) {
  2425.         split[j]=split[j].split('%').join('.');
  2426.     }
  2427.     return split.join('');
  2428. };
  2429. Title.prototype.anchorFromUtf=function(str) {
  2430.     this.anchor=encodeURIComponent(str.split(' ').join('_'))
  2431.     .split('%3A').join(':').split("'").join('%27').split('%').join('.');
  2432. };
  2433. Title.fromURL=function(h) {
  2434.     return new Title().fromURL(h);
  2435. };
  2436. Title.prototype.fromURL=function(h) {
  2437.     if (typeof h != 'string') {
  2438.         this.value=null;
  2439.         return this;
  2440.     }
  2441.  
  2442.     // NOTE : playing with decodeURI, encodeURI, escape, unescape,
  2443.     // we seem to be able to replicate the IE borked encoding
  2444.  
  2445.     // IE doesn't do this new-fangled utf-8 thing.
  2446.     // and it's worse than that.
  2447.     // IE seems to treat the query string differently to the rest of the url
  2448.     // the query is treated as bona-fide utf8, but the first bit of the url is pissed around with
  2449.  
  2450.     // we fix up & for all browsers, just in case.
  2451.     var splitted=h.split('?');
  2452.     splitted[0]=splitted[0].split('&').join('%26');
  2453.  
  2454.     if (pg.flag.linksLikeIE6) {
  2455.         splitted[0]=encodeURI(decode_utf8(splitted[0]));
  2456.     }
  2457.  
  2458.     h=splitted.join('?');
  2459.  
  2460.     var contribs=pg.re.contribs.exec(h);
  2461.     if (contribs !== null) {
  2462.         if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); }
  2463.         var u=new Title(contribs[3]);
  2464.         this.setUtf(this.decodeNasties(pg.ns.user + ':' + u.stripNamespace()));
  2465.         return this;
  2466.     }
  2467.  
  2468.     var email=pg.re.email.exec(h);
  2469.     if (email !== null) {
  2470.         this.setUtf(this.decodeNasties(pg.ns.user + ':' + new Title(email[3]).stripNamespace()));
  2471.         return this;
  2472.     }
  2473.  
  2474.     var backlinks=pg.re.backlinks.exec(h);
  2475.     if (backlinks) {
  2476.         this.setUtf(this.decodeNasties(new Title(backlinks[3])));
  2477.         return this;
  2478.     }
  2479.  
  2480.     // no more special cases to check --
  2481.     // hopefully it's not a disguised user-related or specially treated special page
  2482.     var m=pg.re.main.exec(h);
  2483.     if(m===null) { this.value=null; }
  2484.     else {
  2485.         var fromBotInterface = /[?](.+[&])?title=/.test(h);
  2486.         if (fromBotInterface) {
  2487.             m[2]=m[2].split('+').join('_');
  2488.         }
  2489.         var extracted = m[2] + (m[3] ? '#' + m[3] : '');
  2490.         if (/%25[0-9A-Fa-f]{2}/.test(extracted)) {
  2491.             // Fix Safari issue
  2492.             // Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3.
  2493.             this.setUtf(decodeURIComponent(unescape(extracted)));
  2494.         } else {
  2495.             this.setUtf(this.decodeNasties(extracted));
  2496.         }
  2497.     }
  2498.     return this;
  2499. };
  2500. Title.prototype.decodeNasties=function(txt) {
  2501.     var ret= this.decodeEscapes(decodeURI(txt));
  2502.     ret = ret.replace(/[_ ]*$/, '');
  2503.     return ret;
  2504. };
  2505. Title.prototype.decodeEscapes=function(txt) {
  2506.     var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/);
  2507.     var len=split.length;
  2508.     for (var i=1; i<len; i=i+2) {
  2509.         // FIXME is decodeURIComponent better?
  2510.         split[i]=unescape(split[i]);
  2511.     }
  2512.     return split.join('');
  2513. };
  2514. Title.fromAnchor=function(a) {
  2515.     return new Title().fromAnchor(a);
  2516. };
  2517. Title.prototype.fromAnchor=function(a) {
  2518.     if (!a) { this.value=null; return this; }
  2519.     return this.fromURL(a.href);
  2520. };
  2521. Title.fromWikiText=function(txt) {
  2522.     return new Title().fromWikiText(txt);
  2523. };
  2524. Title.prototype.fromWikiText=function(txt) {
  2525.     // FIXME - testing needed
  2526.     if (!pg.flag.linksLikeIE6) { txt=myDecodeURI(txt); }
  2527.     this.setUtf(txt);
  2528.     return this;
  2529. };
  2530. Title.prototype.hintValue=function(){
  2531.     if(!this.value) { return ''; }
  2532.     return safeDecodeURI(this.value);
  2533. };
  2534. //<NOLITE>
  2535. Title.prototype.toUserName=function(withNs) {
  2536.     if (this.namespace() != pg.ns.user && this.namespace() != pg.ns.usertalk) {
  2537.         this.value=null;
  2538.         return;
  2539.     }
  2540.     this.value = (withNs ? pg.ns.user + ':' : '') + this.stripNamespace().split('/')[0];
  2541. };
  2542. Title.prototype.userName=function(withNs) {
  2543.     var t=(new Title(this.value));
  2544.     t.toUserName(withNs);
  2545.     if (t.value) { return t; }
  2546.     return null;
  2547. };
  2548. Title.prototype.toTalkPage=function() {
  2549.     // convert article to a talk page, or if we can't return null
  2550.     // or, in other words, return null if this ALREADY IS a talk page
  2551.     // and return the corresponding talk page otherwise
  2552.     if (this.value===null) { return null; }
  2553.     var talkRegex=namespaceListToRegex(pg.ns.talkList);
  2554.     if (talkRegex.exec(this.value)) { this.value=null; return null;}
  2555.  
  2556.     var nsReg=namespaceListToRegex(pg.ns.withTalkList);
  2557.     var splitted=this.value.parenSplit(nsReg);
  2558.     if (splitted.length<2) {
  2559.         this.value= (pg.ns.talkList[0]+':'+this.value).split(' ').join('_');
  2560.         return this.value;
  2561.     }
  2562.     for (var i=0; i< pg.ns.withTalkList.length; ++i) {
  2563.         if (splitted[1]==pg.ns.withTalkList[i]) {
  2564.             splitted[1]=pg.ns.talkList[i];
  2565.             this.value=splitted.join(':').substring(1).split(' ').join('_');
  2566.             return this.value;
  2567.         }
  2568.     }
  2569.     this.value=null;
  2570.     return null;
  2571. };
  2572. //</NOLITE>
  2573. Title.prototype.namespace=function() {
  2574.     var n=this.value.indexOf(':');
  2575.     if (n<0) { return ''; }
  2576.     var list=pg.ns.list;
  2577.     for (var i=0; i<list.length; ++i) {
  2578.         if (upcaseFirst(list[i]) == this.value.substring(0,n)) { return list[i]; }
  2579.     }
  2580.     return '';
  2581. };
  2582. //<NOLITE>
  2583. Title.prototype.talkPage=function() {
  2584.     var t=new Title(this.value);
  2585.     t.toTalkPage();
  2586.     if (t.value) { return t; }
  2587.     return null;
  2588. };
  2589. Title.prototype.isTalkPage=function() {
  2590.     if (this.talkPage()===null) { return true; }
  2591.     return false;
  2592. };
  2593. Title.prototype.toArticleFromTalkPage=function() {
  2594.     var talkRegex=namespaceListToRegex(pg.ns.talkList);
  2595.     var splitted=this.value.parenSplit(talkRegex);
  2596.     if (splitted.length < 2 || splitted[0].length > 0) { this.value=null; return null; }
  2597.     if (splitted[1]==pg.ns.talkList[0]) {
  2598.         splitted[1]='';
  2599.         this.value=splitted.join(':').substring(2).split(' ').join('_');
  2600.         return this.value;
  2601.     }
  2602.     for (var i=1; i< pg.ns.talkList.length; ++i) {
  2603.         if (splitted[1]==pg.ns.talkList[i] || splitted[1]==pg.ns.talkList[i].split(' ').join('_')) {
  2604.             splitted[1]=pg.ns.withTalkList[i];
  2605.             this.value= splitted.join(':').substring(1).split(' ').join('_');
  2606.             return this.value;
  2607.             }
  2608.     }
  2609.     this.value=null;
  2610.     return this.value;
  2611. };
  2612. Title.prototype.articleFromTalkPage=function() {
  2613.     var t=new Title(this.value);
  2614.     t.toArticleFromTalkPage();
  2615.     if (t.value) { return t; }
  2616.     return null;
  2617. };
  2618. Title.prototype.articleFromTalkOrArticle=function() {
  2619.     var t=new Title(this.value);
  2620.     if ( t.toArticleFromTalkPage() ) { return t; }
  2621.     return this;
  2622. };
  2623. Title.prototype.isIpUser=function() {
  2624.     return pg.re.ipUser.test(this.userName());
  2625. };
  2626. //</NOLITE>
  2627. Title.prototype.stripNamespace=function(){ // returns a string, not a Title
  2628.     var n=this.value.indexOf(':');
  2629.     if (n<0) { return this.value; }
  2630.     var list=pg.ns.list;
  2631.     for (var i=0; i<list.length; ++i) {
  2632.         if (upcaseFirst(list[i]) == this.value.substring(0,n)) { return this.value.substring(n+1); }
  2633.     }
  2634.     return this.value;
  2635. };
  2636. Title.prototype.setUtf=function(value){
  2637.     if (!value) { this.value=''; return; }
  2638.     var anch=value.indexOf('#');
  2639.     if(anch < 0) { this.value=value.split('_').join(' '); this.anchor=''; return; }
  2640.     this.value=value.substring(0,anch).split('_').join(' ');
  2641.     this.anchor=value.substring(anch+1);
  2642.     this.ns=null; // wait until namespace() is called
  2643. };
  2644. Title.prototype.setUrl=function(urlfrag) {
  2645.     var anch=urlfrag.indexOf('#');
  2646.     this.value=safeDecodeURI(urlfrag.substring(0,anch));
  2647.     this.anchor=value.substring(anch+1);
  2648. };
  2649. Title.prototype.append=function(x){
  2650.     this.setUtf(this.value + x);
  2651. };
  2652. Title.prototype.urlString=function(x) {
  2653.     x || ( x={} );
  2654.     var v=this.toString(true);
  2655.     if (!x.omitAnchor && this.anchor) { v+= '#' + this.urlAnchor(); }
  2656.     if (!x.keepSpaces) { v=v.split(' ').join('_'); }
  2657.     return encodeURI(v).split('&').join('%26').split('?').join('%3F').split('+').join('%2B');
  2658. };
  2659. Title.prototype.removeAnchor=function() {
  2660.     return new Title(this.toString(true));
  2661. };
  2662. Title.prototype.toUrl=function() {
  2663.     return pg.wiki.titlebase + this.urlString();
  2664. };
  2665.  
  2666.  
  2667. function paramValue(param, url) {
  2668.     var s=url.parenSplit(RegExp('[?&]' + literalizeRegex(param) + '=([^?&]*)'));
  2669.     if (!url) { return null; }
  2670.     return s[1] || null;
  2671. }
  2672.  
  2673. function parseParams(url) {
  2674.     var ret={};
  2675.     if (url.indexOf('?')==-1) { return ret; }
  2676.     var s=url.split('?').slice(1).join();
  2677.     var t=s.split('&');
  2678.     for (var i=0; i<t.length; ++i) {
  2679.         var z=t[i].split('=');
  2680.         z.push(null);
  2681.         ret[z[0]]=z[1];
  2682.     }
  2683.     return ret;
  2684. }
  2685.  
  2686. // all sorts of stuff here
  2687. // FIXME almost everything needs to be rewritten
  2688.  
  2689. function oldidFromAnchor(a) { return paramValue('oldid', a.href); }
  2690. //function diffFromAnchor(a) { return paramValue('diff', a.href); }
  2691.  
  2692.  
  2693. function wikiMarkupToAddressFragment (str) { // for images
  2694.     var ret = safeDecodeURI(str);
  2695.     ret = ret.split(' ').join('_');
  2696.     ret = encodeURI(ret);
  2697.     return ret;
  2698. }
  2699.  
  2700. // (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup)
  2701. // (b) change spaces to underscores
  2702. // (c) encodeURI (just the straight one, no pg.re.urlNoPopup)
  2703.  
  2704. function myDecodeURI (str) {
  2705.     var ret;
  2706.     // FIXME decodeURIComponent??
  2707.     try { ret=decodeURI(str.toString()); }
  2708.     catch (summat) { return str; }
  2709.     for (var i=0; i<pg.misc.decodeExtras.length; ++i) {
  2710.         var from=pg.misc.decodeExtras[i].from;
  2711.         var to=pg.misc.decodeExtras[i].to;
  2712.         ret=ret.split(from).join(to);
  2713.     }
  2714.     return ret;
  2715. }
  2716.  
  2717. function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; }
  2718.  
  2719. ///////////
  2720. // TESTS //
  2721. ///////////
  2722.  
  2723. //<NOLITE>
  2724. function isIpUser(user) {return pg.re.ipUser.test(user);}
  2725.  
  2726. function isDisambig(data, article) {
  2727.     if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
  2728.     return ! article.isTalkPage() && pg.re.disambig.test(data);
  2729. }
  2730.  
  2731. function stubCount(data, article) {
  2732.     if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; }
  2733.     var sectStub=0;
  2734.     var realStub=0;
  2735.     if (pg.re.stub.test(data)) {
  2736.         var s=data.parenSplit(pg.re.stub);
  2737.         for (var i=1; i<s.length; i=i+2) {
  2738.             if (s[i]) { ++sectStub; }
  2739.             else { ++realStub; }
  2740.         }
  2741.     }
  2742.     return { real: realStub, sect: sectStub };
  2743. }
  2744.  
  2745. function isValidImageName(str){ // extend as needed...
  2746.     return ( str.indexOf('{') == -1 );
  2747. }
  2748.  
  2749. function isInStrippableNamespace(article) {
  2750.     return ( findInArray( pg.ns.nonArticleList, article.namespace() ) > -1 );
  2751. }
  2752.  
  2753. function isInMainNamespace(article) { return !isInStrippableNamespace(article); }
  2754.  
  2755. function anchorContainsImage(a) {
  2756.     // iterate over children of anchor a
  2757.     // see if any are images
  2758.     if (a===null) { return false; }
  2759.     kids=a.childNodes;
  2760.     for (var i=0; i<kids.length; ++i) { if (kids[i].nodeName=='IMG') { return true; } }
  2761.     return false;
  2762. }
  2763. //</NOLITE>
  2764. function isPopupLink(a) {
  2765.     // NB for performance reasons, TOC links generally return true
  2766.     // they should be stripped out later
  2767.  
  2768.     if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); }
  2769.     if (a.inNopopupSpan || a.className=='sortheader') { return false; }
  2770.  
  2771.     // FIXME is this faster inline?
  2772.     //if (a.onmousedown || a.getAttribute('nopopup')) { return false; }
  2773.     var h=a.href;
  2774.     if (!pg.re.basenames.test(h)) { return false; }
  2775.     if ( !pg.re.urlNoPopup.test(h) ) { return true;    }
  2776.     return (
  2777.         (pg.re.email.test(h) || pg.re.contribs.test(h) || pg.re.backlinks.test(h)) &&
  2778.         h.indexOf('&limit=') == -1 );
  2779. }
  2780.  
  2781. function markNopopupSpanLinks() {
  2782.     var s=document.getElementsByTagName('span');
  2783.     for (var i=0; i<s.length; ++i) {
  2784.         if (s[i].className && s[i].className.toLowerCase()=='nopopups') {
  2785.             var as=s[i].getElementsByTagName('a');
  2786.             for (var j=0; j<as.length; ++j) {
  2787.                 as[j].inNopopupSpan=true;
  2788.             }
  2789.         }
  2790.     }
  2791.     markNopopupSpanLinks.done=true;
  2792. }
  2793. // ENDFILE: titles.js
  2794. // STARTFILE: cookies.js
  2795. //<NOLITE>
  2796. //////////////////////////////////////////////////
  2797. // Cookie handling
  2798. // from http://www.quirksmode.org/js/cookies.html
  2799.  
  2800. var Cookie= {
  2801.     create: function(name,value,days)
  2802.     {
  2803.         var expires;
  2804.         if (days)
  2805.         {
  2806.             var date = new Date();
  2807.             date.setTime(date.getTime()+(days*24*60*60*1000));
  2808.             expires = "; expires="+date.toGMTString();
  2809.         }
  2810.         else { expires = ""; }
  2811.         document.cookie = name+"="+value+expires+"; path=/";
  2812.     },
  2813.  
  2814.     read: function(name)
  2815.     {
  2816.         var nameEQ = name + "=";
  2817.         var ca = document.cookie.split(';');
  2818.         for(var i=0;i < ca.length;i++)
  2819.         {
  2820.             var c = ca[i];
  2821.             while (c.charAt(0)==' ') { c = c.substring(1,c.length); }
  2822.             if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
  2823.         }
  2824.         return null;
  2825.     },
  2826.  
  2827.     erase: function(name)
  2828.     {
  2829.         Cookie.create(name,"",-1);
  2830.     }
  2831. };
  2832. //</NOLITE>
  2833. // ENDFILE: cookies.js
  2834. // STARTFILE: getpage.js
  2835. //////////////////////////////////////////////////
  2836. // Wiki-specific downloading
  2837. //
  2838.  
  2839. // Schematic for a getWiki call
  2840. //
  2841. //   getWiki->-getPageWithCaching
  2842. //                    |
  2843. //       false        |          true
  2844. // getPage<-[findPictureInCache]->-onComplete(a fake download)
  2845. //   \.
  2846. //     (async)->addPageToCache(download)->-onComplete(download)
  2847.  
  2848.  
  2849. /** @todo {document}
  2850.     @param {Title} article
  2851.     @param {Function} onComplete
  2852.     @param {integer} oldid
  2853.     @param {Navapopup} owner
  2854. */
  2855. function getWiki(article, onComplete, oldid, owner) {
  2856.     // set ctype=text/css to get around opera gzip bug
  2857.     var url = pg.wiki.titlebase + article.removeAnchor().urlString() +
  2858.         '&action=raw&ctype=text/css';
  2859.     if (oldid || oldid===0 || oldid==='0') { url += '&oldid='+oldid; }
  2860.     url += '&maxage=0&smaxage=0';
  2861.  
  2862.     getPageWithCaching(url, onComplete, owner);
  2863. }
  2864.  
  2865. // check cache to see if page exists
  2866.  
  2867. function getPageWithCaching(url, onComplete, owner) {
  2868.     log('getPageWithCaching, url='+url);
  2869.     var i=findInPageCache(url);
  2870.     if (i > -1) {
  2871.         var d=fakeDownload(url, owner.idNumber, onComplete,
  2872.                    pg.cache.pages[i].data, pg.cache.pages[i].lastModified,
  2873.                    owner);
  2874.     } else {
  2875.         var d=getPage(url, onComplete, owner);
  2876.         if (d && owner && owner.addDownload) {
  2877.             owner.addDownload(d);
  2878.             d.owner=owner;
  2879.         }
  2880.     }
  2881. }
  2882.  
  2883. function getPage(url, onComplete, owner) {
  2884.     log('getPage');
  2885.     var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d);} };
  2886.     return startDownload(url, owner.idNumber, callback);
  2887. }
  2888.  
  2889. function findInPageCache(url) {
  2890.     for (var i=0; i<pg.cache.pages.length; ++i) {
  2891.         if (url==pg.cache.pages[i].url) { return i; }
  2892.     }
  2893.     return -1;
  2894. }
  2895.  
  2896. function addPageToCache(download) {
  2897.     log('addPageToCache '+download.url);
  2898.     var page = {url: download.url, data: download.data, lastModified: download.lastModified};
  2899.     return pg.cache.pages.push(page);
  2900. }
  2901. // ENDFILE: getpage.js
  2902. // STARTFILE: md5-2.2alpha.js
  2903. //<NOLITE>
  2904. /*
  2905.  * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
  2906.  * Digest Algorithm, as defined in RFC 1321.
  2907.  * Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005
  2908.  * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
  2909.  * Distributed under the BSD License
  2910.  * See http://pajhome.org.uk/crypt/md5 for more info.
  2911.  */
  2912.  
  2913. /*
  2914.  * Configurable variables. You may need to tweak these to be compatible with
  2915.  * the server-side, but the defaults work in most cases.
  2916.  */
  2917. var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase         */
  2918. var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
  2919.  
  2920. /*
  2921.  * These are the functions you'll usually want to call
  2922.  * They take string arguments and return either hex or base-64 encoded strings
  2923.  */
  2924. function hex_md5(s)    { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
  2925. function b64_md5(s)    { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
  2926. function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
  2927. function hex_hmac_md5(k, d)
  2928.   { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
  2929. function b64_hmac_md5(k, d)
  2930.   { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
  2931. function any_hmac_md5(k, d, e)
  2932.   { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
  2933.  
  2934. /*
  2935.  * Perform a simple self-test to see if the VM is working
  2936.  */
  2937. function md5_vm_test()
  2938. {
  2939.   return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
  2940. }
  2941.  
  2942. /*
  2943.  * Calculate the MD5 of a raw string
  2944.  */
  2945. function rstr_md5(s)
  2946. {
  2947.   return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
  2948. }
  2949.  
  2950. /*
  2951.  * Calculate the HMAC-MD5, of a key and some data (raw strings)
  2952.  */
  2953. function rstr_hmac_md5(key, data)
  2954. {
  2955.   var bkey = rstr2binl(key);
  2956.   if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
  2957.  
  2958.   var ipad = Array(16), opad = Array(16);
  2959.   for(var i = 0; i < 16; i++)
  2960.   {
  2961.     ipad[i] = bkey[i] ^ 0x36363636;
  2962.     opad[i] = bkey[i] ^ 0x5C5C5C5C;
  2963.   }
  2964.  
  2965.   var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
  2966.   return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
  2967. }
  2968.  
  2969. /*
  2970.  * Convert a raw string to a hex string
  2971.  */
  2972. function rstr2hex(input)
  2973. {
  2974.   var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  2975.   var output = "";
  2976.   var x;
  2977.   for(var i = 0; i < input.length; i++)
  2978.   {
  2979.     x = input.charCodeAt(i);
  2980.     output += hex_tab.charAt((x >>> 4) & 0x0F)
  2981.        +  hex_tab.charAt( x           & 0x0F);
  2982.   }
  2983.   return output;
  2984. }
  2985.  
  2986. /*
  2987.  * Convert a raw string to a base-64 string
  2988.  */
  2989. function rstr2b64(input)
  2990. {
  2991.   var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2992.   var output = "";
  2993.   var len = input.length;
  2994.   for(var i = 0; i < len; i += 3)
  2995.   {
  2996.     var triplet = (input.charCodeAt(i) << 16)
  2997.         | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
  2998.         | (i + 2 < len ? input.charCodeAt(i+2)        : 0);
  2999.     for(var j = 0; j < 4; j++)
  3000.     {
  3001.       if(i * 8 + j * 6 > input.length * 8) output += b64pad;
  3002.       else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
  3003.     }
  3004.   }
  3005.   return output;
  3006. }
  3007.  
  3008. /*
  3009.  * Convert a raw string to an arbitrary string encoding
  3010.  */
  3011. function rstr2any(input, encoding)
  3012. {
  3013.   var divisor = encoding.length;
  3014.   var remainders = Array();
  3015.   var i, q, x, quotient;
  3016.  
  3017.   /* Convert to an array of 16-bit big-endian values, forming the dividend */
  3018.   var dividend = Array(input.length / 2);
  3019.   for(i = 0; i < dividend.length; i++)
  3020.   {
  3021.     dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  3022.   }
  3023.  
  3024.   /*
  3025.    * Repeatedly perform a long division. The binary array forms the dividend,
  3026.    * the length of the encoding is the divisor. Once computed, the quotient
  3027.    * forms the dividend for the next step. We stop when the dividend is zero.
  3028.    * All remainders are stored for later use.
  3029.    */
  3030.   while(dividend.length > 0)
  3031.   {
  3032.     quotient = Array();
  3033.     x = 0;
  3034.     for(i = 0; i < dividend.length; i++)
  3035.     {
  3036.       x = (x << 16) + dividend[i];
  3037.       q = Math.floor(x / divisor);
  3038.       x -= q * divisor;
  3039.       if(quotient.length > 0 || q > 0)
  3040.     quotient[quotient.length] = q;
  3041.     }
  3042.     remainders[remainders.length] = x;
  3043.     dividend = quotient;
  3044.   }
  3045.  
  3046.   /* Convert the remainders to the output string */
  3047.   var output = "";
  3048.   for(i = remainders.length - 1; i >= 0; i--)
  3049.     output += encoding.charAt(remainders[i]);
  3050.  
  3051.   return output;
  3052. }
  3053.  
  3054. /*
  3055.  * Encode a string as utf-8.
  3056.  * For efficiency, this assumes the input is valid utf-16.
  3057.  */
  3058. function str2rstr_utf8(input)
  3059. {
  3060.   var output = "";
  3061.   var i = -1;
  3062.   var x, y;
  3063.  
  3064.   while(++i < input.length)
  3065.   {
  3066.     /* Decode utf-16 surrogate pairs */
  3067.     x = input.charCodeAt(i);
  3068.     y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
  3069.     if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
  3070.     {
  3071.       x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
  3072.       i++;
  3073.     }
  3074.  
  3075.     /* Encode output as utf-8 */
  3076.     if(x <= 0x7F)
  3077.       output += String.fromCharCode(x);
  3078.     else if(x <= 0x7FF)
  3079.       output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
  3080.                     0x80 | ( x           & 0x3F));
  3081.     else if(x <= 0xFFFF)
  3082.       output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
  3083.                     0x80 | ((x >>> 6 ) & 0x3F),
  3084.                     0x80 | ( x           & 0x3F));
  3085.     else if(x <= 0x1FFFFF)
  3086.       output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
  3087.                     0x80 | ((x >>> 12) & 0x3F),
  3088.                     0x80 | ((x >>> 6 ) & 0x3F),
  3089.                     0x80 | ( x           & 0x3F));
  3090.   }
  3091.   return output;
  3092. }
  3093.  
  3094. /*
  3095.  * Encode a string as utf-16
  3096.  */
  3097. function str2rstr_utf16le(input)
  3098. {
  3099.   var output = "";
  3100.   for(var i = 0; i < input.length; i++)
  3101.     output += String.fromCharCode( input.charCodeAt(i)          & 0xFF,
  3102.                   (input.charCodeAt(i) >>> 8) & 0xFF);
  3103.   return output;
  3104. }
  3105.  
  3106. function str2rstr_utf16be(input)
  3107. {
  3108.   var output = "";
  3109.   for(var i = 0; i < input.length; i++)
  3110.     output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
  3111.                    input.charCodeAt(i)          & 0xFF);
  3112.   return output;
  3113. }
  3114.  
  3115. /*
  3116.  * Convert a raw string to an array of little-endian words
  3117.  * Characters >255 have their high-byte silently ignored.
  3118.  */
  3119. function rstr2binl(input)
  3120. {
  3121.   var output = Array(input.length >> 2);
  3122.   for(var i = 0; i < output.length; i++)
  3123.     output[i] = 0;
  3124.   for(var i = 0; i < input.length * 8; i += 8)
  3125.     output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
  3126.   return output;
  3127. }
  3128.  
  3129. /*
  3130.  * Convert an array of little-endian words to a string
  3131.  */
  3132. function binl2rstr(input)
  3133. {
  3134.   var output = "";
  3135.   for(var i = 0; i < input.length * 32; i += 8)
  3136.     output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
  3137.   return output;
  3138. }
  3139.  
  3140. /*
  3141.  * Calculate the MD5 of an array of little-endian words, and a bit length.
  3142.  */
  3143. function binl_md5(x, len)
  3144. {
  3145.   /* append padding */
  3146.   x[len >> 5] |= 0x80 << ((len) % 32);
  3147.   x[(((len + 64) >>> 9) << 4) + 14] = len;
  3148.  
  3149.   var a =  1732584193;
  3150.   var b = -271733879;
  3151.   var c = -1732584194;
  3152.   var d =  271733878;
  3153.  
  3154.   for(var i = 0; i < x.length; i += 16)
  3155.   {
  3156.     var olda = a;
  3157.     var oldb = b;
  3158.     var oldc = c;
  3159.     var oldd = d;
  3160.  
  3161.     a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
  3162.     d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
  3163.     c = md5_ff(c, d, a, b, x[i+ 2], 17,     606105819);
  3164.     b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
  3165.     a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
  3166.     d = md5_ff(d, a, b, c, x[i+ 5], 12,     1200080426);
  3167.     c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
  3168.     b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
  3169.     a = md5_ff(a, b, c, d, x[i+ 8], 7 ,     1770035416);
  3170.     d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
  3171.     c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
  3172.     b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
  3173.     a = md5_ff(a, b, c, d, x[i+12], 7 ,     1804603682);
  3174.     d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
  3175.     c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
  3176.     b = md5_ff(b, c, d, a, x[i+15], 22,     1236535329);
  3177.  
  3178.     a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
  3179.     d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
  3180.     c = md5_gg(c, d, a, b, x[i+11], 14,     643717713);
  3181.     b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
  3182.     a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
  3183.     d = md5_gg(d, a, b, c, x[i+10], 9 ,     38016083);
  3184.     c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
  3185.     b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
  3186.     a = md5_gg(a, b, c, d, x[i+ 9], 5 ,     568446438);
  3187.     d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
  3188.     c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
  3189.     b = md5_gg(b, c, d, a, x[i+ 8], 20,     1163531501);
  3190.     a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
  3191.     d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
  3192.     c = md5_gg(c, d, a, b, x[i+ 7], 14,     1735328473);
  3193.     b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
  3194.  
  3195.     a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
  3196.     d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
  3197.     c = md5_hh(c, d, a, b, x[i+11], 16,     1839030562);
  3198.     b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
  3199.     a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
  3200.     d = md5_hh(d, a, b, c, x[i+ 4], 11,     1272893353);
  3201.     c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
  3202.     b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
  3203.     a = md5_hh(a, b, c, d, x[i+13], 4 ,     681279174);
  3204.     d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
  3205.     c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
  3206.     b = md5_hh(b, c, d, a, x[i+ 6], 23,     76029189);
  3207.     a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
  3208.     d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
  3209.     c = md5_hh(c, d, a, b, x[i+15], 16,     530742520);
  3210.     b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
  3211.  
  3212.     a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
  3213.     d = md5_ii(d, a, b, c, x[i+ 7], 10,     1126891415);
  3214.     c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
  3215.     b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
  3216.     a = md5_ii(a, b, c, d, x[i+12], 6 ,     1700485571);
  3217.     d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
  3218.     c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
  3219.     b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
  3220.     a = md5_ii(a, b, c, d, x[i+ 8], 6 ,     1873313359);
  3221.     d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
  3222.     c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
  3223.     b = md5_ii(b, c, d, a, x[i+13], 21,     1309151649);
  3224.     a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
  3225.     d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
  3226.     c = md5_ii(c, d, a, b, x[i+ 2], 15,     718787259);
  3227.     b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
  3228.  
  3229.     a = safe_add(a, olda);
  3230.     b = safe_add(b, oldb);
  3231.     c = safe_add(c, oldc);
  3232.     d = safe_add(d, oldd);
  3233.   }
  3234.   return Array(a, b, c, d);
  3235. }
  3236.  
  3237. /*
  3238.  * These functions implement the four basic operations the algorithm uses.
  3239.  */
  3240. function md5_cmn(q, a, b, x, s, t)
  3241. {
  3242.   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
  3243. }
  3244. function md5_ff(a, b, c, d, x, s, t)
  3245. {
  3246.   return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
  3247. }
  3248. function md5_gg(a, b, c, d, x, s, t)
  3249. {
  3250.   return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
  3251. }
  3252. function md5_hh(a, b, c, d, x, s, t)
  3253. {
  3254.   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
  3255. }
  3256. function md5_ii(a, b, c, d, x, s, t)
  3257. {
  3258.   return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
  3259. }
  3260.  
  3261. /*
  3262.  * Add integers, wrapping at 2^32. This uses 16-bit operations internally
  3263.  * to work around bugs in some JS interpreters.
  3264.  */
  3265. function safe_add(x, y)
  3266. {
  3267.   var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  3268.   var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  3269.   return (msw << 16) | (lsw & 0xFFFF);
  3270. }
  3271.  
  3272. /*
  3273.  * Bitwise rotate a 32-bit number to the left.
  3274.  */
  3275. function bit_rol(num, cnt)
  3276. {
  3277.   return (num << cnt) | (num >>> (32 - cnt));
  3278. }
  3279. //</NOLITE>
  3280. // ENDFILE: md5-2.2alpha.js
  3281. // STARTFILE: parensplit.js
  3282. //////////////////////////////////////////////////
  3283. // parenSplit
  3284.  
  3285. // String.prototype.parenSplit should do what ECMAscript says
  3286. // String.prototype.split does, interspersing paren matches between
  3287. // the split elements
  3288.  
  3289. if (String('abc'.split(/(b)/))!='a,b,c') {
  3290.     // broken String.split, e.g. konq, IE
  3291.     String.prototype.parenSplit=function (re) {
  3292.         re=nonGlobalRegex(re);
  3293.         var s=this;
  3294.         var m=re.exec(s);
  3295.         var ret=[];
  3296.         while (m && s) {
  3297.             // without the following loop, we have
  3298.             // 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/)
  3299.             for(var i=0; i<m.length; ++i) {
  3300.                 if (typeof m[i]=='undefined') m[i]='';
  3301.             }
  3302.             ret.push(s.substring(0,m.index));
  3303.             ret = ret.concat(m.slice(1));
  3304.             s=s.substring(m.index + m[0].length);
  3305.             m=re.exec(s);
  3306.         }
  3307.         ret.push(s);
  3308.         return ret;
  3309.     };
  3310. } else {
  3311.     String.prototype.parenSplit=function (re) { return this.split(re); };
  3312.     String.prototype.parenSplit.isNative=true;
  3313. }
  3314.  
  3315. function nonGlobalRegex(re) {
  3316.     var s=re.toString();
  3317.     flags='';
  3318.     for (var j=s.length; s.charAt(j) != '/'; --j) {
  3319.         if (s.charAt(j) != 'g') { flags += s.charAt(j); }
  3320.     }
  3321.     var t=s.substring(1,j);
  3322.     return RegExp(t,flags);
  3323. }
  3324. // ENDFILE: parensplit.js
  3325. // STARTFILE: tools.js
  3326. // IE madness with encoding
  3327. // ========================
  3328. //
  3329. // suppose throughout that the page is in utf8, like wikipedia
  3330. //
  3331. // if a is an anchor DOM element and a.href should consist of
  3332. //
  3333. // http://host.name.here/wiki/foo?bar=baz
  3334. //
  3335. // then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie))
  3336. // but IE gives bar=baz correctly as plain utf8
  3337. //
  3338. // ---------------------------------
  3339. //
  3340. // IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here.
  3341. //
  3342. // ---------------------------------
  3343. //
  3344. // summat else
  3345.  
  3346. // Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm
  3347.  
  3348. //<NOLITE>
  3349. function encode_utf8(rohtext) {
  3350.     // dient der Normalisierung des Zeilenumbruchs
  3351.     rohtext = rohtext.replace(/\r\n/g,"\n");
  3352.     var utftext = "";
  3353.     for(var n=0; n<rohtext.length; n++)
  3354.     {
  3355.         // ermitteln des Unicodes des  aktuellen Zeichens
  3356.         var c=rohtext.charCodeAt(n);
  3357.         // alle Zeichen von 0-127 => 1byte
  3358.         if (c<128)
  3359.             utftext += String.fromCharCode(c);
  3360.         // alle Zeichen von 127 bis 2047 => 2byte
  3361.         else if((c>127) && (c<2048)) {
  3362.             utftext += String.fromCharCode((c>>6)|192);
  3363.             utftext += String.fromCharCode((c&63)|128);}
  3364.         // alle Zeichen von 2048 bis 66536 => 3byte
  3365.         else {
  3366.             utftext += String.fromCharCode((c>>12)|224);
  3367.             utftext += String.fromCharCode(((c>>6)&63)|128);
  3368.             utftext += String.fromCharCode((c&63)|128);}
  3369.     }
  3370.     return utftext;
  3371. }
  3372.  
  3373. function getJsObj(json) {
  3374.     try {
  3375.         var json_ret = WikiLookjsonParse('(' + json + ')');
  3376.     } catch (someError) {
  3377.         errlog('Something went wrong with getJsobj, json='+json);
  3378.         return 1;
  3379.     }
  3380.     if( json_ret['warnings'] ) {
  3381.         for( var w=0; w < json_ret['warnings'].length; w++ ) {
  3382.             log( json_ret['warnings'][w]['*'] );
  3383.         }
  3384.     } else if ( json_ret['error'] ) {
  3385.         errlog( json_ret['error'].code + ': ' + json_ret['error'].info );
  3386.     }
  3387.     return json_ret;
  3388. }
  3389.  
  3390. function anyChild(obj) {
  3391.     for (var p in obj) {
  3392.         return obj[p];
  3393.     }
  3394.     return null;
  3395. }
  3396.  
  3397. //</NOLITE>
  3398.  
  3399. function decode_utf8(utftext) {
  3400.     var plaintext = ""; var i=0, c=0, c1=0, c2=0;
  3401.     // while-Schleife, weil einige Zeichen uebersprungen werden
  3402.     while(i<utftext.length)
  3403.     {
  3404.         c = utftext.charCodeAt(i);
  3405.         if (c<128) {
  3406.             plaintext += String.fromCharCode(c);
  3407.             i++;}
  3408.         else if((c>191) && (c<224)) {
  3409.             c2 = utftext.charCodeAt(i+1);
  3410.             plaintext += String.fromCharCode(((c&31)<<6) | (c2&63));
  3411.             i+=2;}
  3412.         else {
  3413.             c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2);
  3414.             plaintext += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63));
  3415.             i+=3;}
  3416.     }
  3417.     return plaintext;
  3418. }
  3419.  
  3420.  
  3421. function upcaseFirst(str) {
  3422.     if (typeof str != typeof '' || str=='') return '';
  3423.     return str.charAt(0).toUpperCase() + str.substring(1);
  3424. }
  3425.  
  3426.  
  3427. function findInArray(arr, foo) {
  3428.     if (!arr || !arr.length) { return -1; }
  3429.     var len=arr.length;
  3430.     for (var i=0; i<len; ++i) { if (arr[i]==foo) { return i; } }
  3431.     return -1;
  3432. }
  3433.  
  3434. function nextOne (array, value) {
  3435.     // NB if the array has two consecutive entries equal
  3436.     //    then this will loop on successive calls
  3437.     var i=findInArray(array, value);
  3438.     if (i<0) { return null; }
  3439.     return array[i+1];
  3440. }
  3441.  
  3442. function literalizeRegex(str){
  3443.     return str.replace(RegExp('([-.|()\\+?*^${}\\[\\]])', 'g'), '\\$1');
  3444. }
  3445.  
  3446. String.prototype.entify=function() {
  3447.     //var shy='­';
  3448.     return this.split('&').join('&').split('<').join('<').split('>').join('>'/*+shy*/).split('"').join('"');
  3449. };
  3450.  
  3451. function findThis(array, value) {
  3452.     if (typeof array.length == 'undefined') { return null; }
  3453.     for (var i=0; i<array.length; ++i) {
  3454.         if (array[i]==value) { return i; }
  3455.     }
  3456.     return null;
  3457. }
  3458.  
  3459. function removeNulls(list) {
  3460.     var ret=[];
  3461.     for (var i=0; i<list.length; ++i) {
  3462.         if (list[i]) {
  3463.             ret.push(list[i]);
  3464.         }
  3465.     }
  3466.     return ret;
  3467. }
  3468. function joinPath(list) {
  3469.     return removeNulls(list).join('/');
  3470. }
  3471.  
  3472.  
  3473. function simplePrintf(str, subs) {
  3474.     if (!str || !subs) { return str; }
  3475.     var ret=[];
  3476.     var s=str.parenSplit(/(%s|\$[0-9]+)/);
  3477.     var i=0;
  3478.     do {
  3479.         ret.push(s.shift());
  3480.         if ( !s.length ) { break; }
  3481.         var cmd=s.shift();
  3482.         if (cmd == '%s') {
  3483.             if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); }
  3484.             ++i;
  3485.         } else {
  3486.             var j=parseInt( cmd.replace('$', ''), 10 ) - 1;
  3487.             if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); }
  3488.         }
  3489.     } while (s.length > 0);
  3490.     return ret.join('');
  3491. }
  3492.  
  3493. function max(a,b){return a<b ? b : a;}
  3494. function min(a,b){return a>b ? b : a;}
  3495.  
  3496. function isString(x) { return (typeof x === 'string' || x instanceof String); }
  3497. //function isNumber(x) { return (typeof x === 'number' || x instanceof Number); }
  3498. function isRegExp(x) { return x instanceof RegExp; }
  3499. function isArray (x) { return x instanceof Array; }
  3500. function isObject(x) { return x instanceof Object; }
  3501. function isFunction(x) {
  3502.     return !isRegExp(x) && (typeof x === 'function' || x instanceof Function);
  3503. }
  3504.  
  3505. function repeatString(s,mult) {
  3506.     var ret='';
  3507.     for (var i=0; i<mult; ++i) { ret += s; }
  3508.     return ret;
  3509. }
  3510.  
  3511. function zeroFill(s, min) {
  3512.     min = min || 2;
  3513.     var t=s.toString();
  3514.     return repeatString('0', min - t.length) + t;
  3515. }
  3516.  
  3517. function map(f, o) {
  3518.     if (isArray(o)) { return map_array(f,o); }
  3519.     return map_object(f,o);
  3520. }
  3521. function map_array(f,o) {
  3522.     var ret=[];
  3523.     for (var i=0; i<o.length; ++i) {
  3524.         ret.push(f(o[i]));
  3525.     }
  3526.     return ret;
  3527. }
  3528. function map_object(f,o) {
  3529.     var ret={};
  3530.     for (var i in o) { ret[o]=f(o[i]); }
  3531.     return ret;
  3532. }
  3533. // ENDFILE: tools.js
  3534. // STARTFILE: dab.js
  3535. //<NOLITE>
  3536. //////////////////////////////////////////////////
  3537. // Dab-fixing code
  3538. //
  3539.  
  3540.  
  3541. function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) {
  3542.     log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget);
  3543.     return changeLinkTargetLink(
  3544.     {newTarget: newTarget,
  3545.             text: newTarget.split(' ').join(' '),
  3546.             hint: tprintf('disambigHint', [newTarget]),
  3547.             summary: simplePrintf(
  3548.                     getValueOf('popupFixDabsSummary'), [friendlyCurrentArticleName, newTarget ]),
  3549.             clickButton: 'wpDiff', minor: true, oldTarget: oldTarget,
  3550.             watch: getValueOf('popupWatchDisambiggedPages'),
  3551.             title: titleToEdit});
  3552. }
  3553.  
  3554. function listLinks(wikitext, oldTarget, titleToEdit) {
  3555.     // mediawiki strips trailing spaces, so we do the same
  3556.     // testcase: http://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633
  3557.     var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi');
  3558.     var ret=[];
  3559.     var splitted=wikitext.parenSplit(reg);
  3560.     // ^[a-z]+ should match interwiki links, hopefully (case-insensitive)
  3561.     // and ^[a-z]* should match those and [[:Category...]] style links too
  3562.     var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory');
  3563.     var friendlyCurrentArticleName= oldTarget.toString();
  3564.     var wikPos = getValueOf('popupDabWiktionary');
  3565.  
  3566.     for (var i=1; i<splitted.length; i=i+3) {
  3567.         if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) {
  3568.             ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) );
  3569.         } /* if */
  3570.     } /* for loop */
  3571.  
  3572.     ret = rmDupesFromSortedList(ret.sort());
  3573.  
  3574.     if (wikPos) {
  3575.         var wikTarget='wiktionary:' +
  3576.             friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' );
  3577.  
  3578.         var meth;
  3579.         if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; }
  3580.         else { meth = 'push'; }
  3581.  
  3582.         ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) );
  3583.     }
  3584.  
  3585.     ret.push(changeLinkTargetLink(
  3586.     { newTarget: null,
  3587.             text: popupString('remove this link').split(' ').join(' '),
  3588.             hint: popupString("remove all links to this disambig page from this article"),
  3589.             clickButton: "wpDiff", oldTarget: oldTarget,
  3590.             summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]),
  3591.             watch: getValueOf('popupWatchDisambiggedPages'),
  3592.             title: titleToEdit
  3593.             }));
  3594.     return ret;
  3595. }
  3596.  
  3597. function rmDupesFromSortedList(list) {
  3598.     var ret=[];
  3599.     for (var i=0; i<list.length; ++i) {
  3600.         if (ret.length===0 || list[i]!=ret[ret.length-1]) { ret.push(list[i]); }
  3601.     }
  3602.     return ret;
  3603. }
  3604.  
  3605. function makeFixDab(data, navpop) {
  3606.     // grab title from parent popup if there is one; default exists in changeLinkTargetLink
  3607.     var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString());
  3608.     var list=listLinks(data, navpop.originalArticle, titleToEdit);
  3609.     if (list.length===0) { log('listLinks returned empty list'); return null; }
  3610.     var html='<hr>' + popupString('Click to disambiguate this link to:') + '<br>';
  3611.     html+=list.join(', ');
  3612.     return html;
  3613. }
  3614.  
  3615.  
  3616. function makeFixDabs(wikiText, navpop) {
  3617.     if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) &&
  3618.         Title.fromURL(location.href).namespace() != pg.ns.special &&
  3619.         navpop.article.talkPage() ) {
  3620.         setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber);
  3621.     }
  3622. }
  3623.  
  3624. function popupRedlinkHTML(article) {
  3625.     return changeLinkTargetLink(
  3626.         { newTarget: null, text: popupString('remove this link').split(' ').join(' '),
  3627.             hint: popupString("remove all links to this page from this article"),
  3628.             clickButton: "wpDiff",
  3629.             oldTarget: article.toString(),
  3630.             summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])});
  3631. }
  3632. //</NOLITE>
  3633. // ENDFILE: dab.js
  3634. // STARTFILE: htmloutput.js
  3635.  
  3636. function appendPopupContent(obj, elementId, popupId, onSuccess) {
  3637.     return setPopupHTML(obj, elementId, popupId, onSuccess, true);
  3638. }
  3639.  
  3640. // this has to use a timer loop as we don't know if the DOM element exists when we want to set the text
  3641. function setPopupHTML (str, elementId, popupId, onSuccess, append) {
  3642.     if (elementId=='popupPreview') {
  3643.     }
  3644.     if (typeof popupId === 'undefined') {
  3645.         //console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100));
  3646.         popupId = pg.idNumber;
  3647.     }
  3648.  
  3649.     var popupElement=content.document.getElementById(elementId+popupId);
  3650.     if (popupElement) {
  3651.         if (!append) { popupElement.innerHTML=''; }
  3652.         if (isString(str)) {
  3653.             popupElement.innerHTML+=str;
  3654.         } else {
  3655.             popupElement.appendChild(str);
  3656.         }
  3657.         if (onSuccess) { onSuccess(); }
  3658.         setTimeout(checkPopupPosition, 100);
  3659.         return true;
  3660.     } else {
  3661.         // call this function again in a little while...
  3662.         setTimeout(function(){
  3663.                 setPopupHTML(str,elementId,popupId,onSuccess);
  3664.             }, 600);
  3665.     }
  3666.     return null;
  3667. }
  3668.  
  3669. //<NOLITE>
  3670. function setImageStatus(str, id) {return; } // setPopupHTML(str, 'popupImageStatus', id);}
  3671. function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);}
  3672. //</NOLITE>
  3673.  
  3674.  
  3675. function fillEmptySpans(args) { return fillEmptySpans2(args); }
  3676.  
  3677. // args.navpopup is mandatory
  3678. // optional: args.redir, args.redirTarget
  3679. // FIXME: ye gods, this is ugly stuff
  3680. function fillEmptySpans2(args) { // if redir is present and true then redirTarget is mandatory
  3681.     var redir=true;
  3682.     if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; }
  3683.     var a=args.navpopup.parentAnchor;
  3684.  
  3685.     var article, hint=null, oldid=null, params={};
  3686.     if (redir && typeof args.redirTarget == typeof {}) {
  3687.         article=args.redirTarget;
  3688.         //hint=article.hintValue();
  3689.     } else {
  3690.         article=(new Title()).fromAnchor(a);
  3691.         hint=a.originalTitle || article.hintValue();
  3692.         params=parseParams(a.href);
  3693.         oldid=(getValueOf('popupHistoricalLinks')) ? params.oldid : null;
  3694.         rcid=params.rcid;
  3695.     }
  3696.     var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params };
  3697.  
  3698.     var structure=pg.structures[getValueOf('popupStructure')];
  3699.     if (typeof structure != 'object') {
  3700.         setPopupHTML('popupError', 'Unknown structure (this should never happen): '+
  3701.                  pg.option.popupStructure, args.navpopup.idNumber);
  3702.         return;
  3703.     }
  3704.     var spans=flatten(pg.misc.layout);
  3705.     var numspans = spans.length;
  3706.     var redirs=pg.misc.redirSpans;
  3707.  
  3708.     for (var i=0; i<numspans; ++i) {
  3709.         var f=findThis(redirs, spans[i]);
  3710.         //log('redir='+redir+', f='+f+', spans[i]='+spans[i]);
  3711.         if ( (f!==null && !redir) || (f===null && redir) ) {
  3712.             //log('skipping this set of the loop');
  3713.             continue;
  3714.         }
  3715.         var structurefn=structure[spans[i]];
  3716.         var setfn = setPopupHTML;
  3717.         if (getValueOf('popupActiveNavlinks') && 
  3718.             (spans[i].indexOf('popupTopLinks')==0 || spans[i].indexOf('popupRedirTopLinks')==0)
  3719.                 ) {
  3720.             setfn = setPopupTipsAndHTML;
  3721.         }
  3722.         switch (typeof structurefn) {
  3723.         case 'function':
  3724.             //log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})');
  3725.             setfn(structurefn(x), spans[i], args.navpopup.idNumber);
  3726.             break;
  3727.         case 'string':
  3728.             setfn(structurefn, spans[i], args.navpopup.idNumber);
  3729.             break;
  3730.         default:
  3731.             errlog('unknown thing with label '+spans[i]);
  3732.             break;
  3733.         }
  3734.     }
  3735. }
  3736.  
  3737. // flatten an array
  3738. function flatten(list, start) {
  3739.     var ret=[];
  3740.     if (typeof start == 'undefined') { start=0; }
  3741.     for (var i=start; i<list.length; ++i) {
  3742.         if (typeof list[i] == typeof []) {
  3743.             return ret.concat(flatten(list[i])).concat(flatten(list, i+1));
  3744.         }
  3745.         else { ret.push(list[i]); }
  3746.     }
  3747.     return ret;
  3748. }
  3749.  
  3750. // Generate html for whole popup
  3751. function popupHTML (a) {
  3752.     getValueOf('popupStructure');
  3753.     var structure=pg.structures[pg.option.popupStructure];
  3754.     if (typeof structure != 'object') {
  3755.         //return 'Unknown structure: '+pg.option.popupStructure;
  3756.         // override user choice
  3757.         pg.option.popupStructure=pg.optionDefault.popupStructure;
  3758.         return popupHTML(a);
  3759.     }
  3760.     if (typeof structure.popupLayout != 'function') { return 'Bad layout'; }
  3761.     pg.misc.layout=structure.popupLayout();
  3762.     if (typeof structure.popupRedirSpans == 'function') { pg.misc.redirSpans=structure.popupRedirSpans(); }
  3763.     else { pg.misc.redirSpans=[]; }
  3764.     return makeEmptySpans(pg.misc.layout, a.navpopup);
  3765. }
  3766.  
  3767. function makeEmptySpans (list, navpop) {
  3768.     var ret='';
  3769.     for (var i=0; i<list.length; ++i) {
  3770.         if (typeof list[i] == typeof '') {
  3771.             ret += emptySpanHTML(list[i], navpop.idNumber, 'div');
  3772.         } else if (typeof list[i] == typeof [] && list[i].length > 0 ) {
  3773.             ret = ret.parenSplit(RegExp('(</[^>]*?>$)')).join(makeEmptySpans(list[i], navpop));
  3774.         } else if (typeof list[i] == typeof {} && list[i].nodeType ) {
  3775.             ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType);
  3776.         }
  3777.     }
  3778.     return ret;
  3779. }
  3780.  
  3781.  
  3782. function emptySpanHTML(name, id, tag, classname) {
  3783.     tag = tag || 'span';
  3784.     if (!classname) { classname = emptySpanHTML.classAliases[name]; }
  3785.     classname = classname || name;
  3786.     if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; }
  3787.     return simplePrintf('<%s id="%s" class="%s"></%s>', [tag, name + id, classname, tag]);
  3788. }
  3789. emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' };
  3790.  
  3791. // generate html for popup image
  3792. // <a id="popupImageLinkn"><img id="popupImagen">
  3793. // where n=idNumber
  3794. function imageHTML(article, idNumber) {
  3795.     return simplePrintf('<a id="popupImageLink$1">' +
  3796.                 '<img align="right" valign="top" border="0" id="popupImg$1" style="display: none; margin-left:4px;"></img>' +
  3797.                 '</a>', [ idNumber ]);
  3798. }
  3799.  
  3800. function popTipsSoonFn(id, when, popData) {
  3801.     when || ( when=250 );
  3802.     var popTips=function(){ setupTooltips(content.document.getElementById(id), false, true, popData); };
  3803.     return function() { setTimeout( popTips, when, popData ); };
  3804. }
  3805.  
  3806. function setPopupTipsAndHTML(html, divname, idnumber, popData) {
  3807.     setPopupHTML(html, divname, idnumber,
  3808.              getValueOf('popupSubpopups') ? 
  3809.              popTipsSoonFn(divname + idnumber, null, popData) : 
  3810.              null);
  3811. }
  3812. // ENDFILE: htmloutput.js
  3813. // STARTFILE: mouseout.js
  3814. //////////////////////////////////////////////////
  3815. // fuzzy checks
  3816.  
  3817. function fuzzyCursorOffMenus(x,y, fuzz, parent) {
  3818.     if (!parent) { return null; }
  3819.     var uls=parent.getElementsByTagName('ul');
  3820.     for (var i=0; i<uls.length; ++i) {
  3821.         if (uls[i].className=='popup_menu') {
  3822.             if (uls[i].offsetWidth > 0) return false;
  3823.         } // else {document.title+='.';}
  3824.     }
  3825.     return true;
  3826. }
  3827.  
  3828. function checkPopupPosition () { // stop the popup running off the right of the screen
  3829.     // FIXME avoid pg.current.link
  3830.     pg.current.link && pg.current.link.navpopup &&
  3831.         pg.current.link.navpopup.limitHorizontalPosition();
  3832. }
  3833.  
  3834. function mouseOutWikiLink () {
  3835.     if (!window.popupsReady || !window.popupsReady()) { return; }
  3836.     //console ('mouseOutWikiLink');
  3837.     var a=this;
  3838.     if (a.navpopup==null) return;
  3839.     if ( ! a.navpopup.isVisible() ) {
  3840.         a.navpopup.banish();
  3841.         return;
  3842.     }
  3843.     Navpopup.tracker.addHook(posCheckerHook(a.navpopup));
  3844. }
  3845.  
  3846. function posCheckerHook(navpop) {
  3847.     return function() {
  3848.         if (!navpop.isVisible()) { return true; /* remove this hook */ }
  3849.         if (Navpopup.tracker.dirty) {
  3850.             return false;
  3851.         }
  3852.         var x=Navpopup.tracker.x, y=Navpopup.tracker.y;
  3853.         var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) ||
  3854.             !fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv);
  3855.  
  3856.         // FIXME it'd be prettier to do this internal to the Navpopup objects
  3857.         var t=getValueOf('popupHideDelay');
  3858.         if (t) { t = t * 1000; }
  3859.         if (!t) {
  3860.             if(!mouseOverNavpop) {
  3861.                 navpop.banish();
  3862.                 return true; /* remove this hook */
  3863.             }
  3864.             return false;
  3865.         }
  3866.         // we have a hide delay set
  3867.         var d=+(new Date());
  3868.         if ( !navpop.mouseLeavingTime ) {
  3869.             navpop.mouseLeavingTime = d;
  3870.             return false;
  3871.         }
  3872.         if ( mouseOverNavpop ) {
  3873.             navpop.mouseLeavingTime=null;
  3874.             return false;
  3875.         }
  3876.         if (d - navpop.mouseLeavingTime > t) {
  3877.             navpop.mouseLeavingTime=null;
  3878.             navpop.banish(); return true; /* remove this hook */
  3879.         }
  3880.         return false;
  3881.     };
  3882. }
  3883.  
  3884. function runStopPopupTimer(navpop) {
  3885.     // at this point, we should have left the link but remain within the popup
  3886.     // so we call this function again until we leave the popup.
  3887.     if (!navpop.stopPopupTimer) {
  3888.         navpop.stopPopupTimer=setInterval(posCheckerHook(navpop), 500);
  3889.         navpop.addHook(function(){clearInterval(navpop.stopPopupTimer);},
  3890.                    'hide', 'before');
  3891.     }
  3892. }
  3893. // ENDFILE: mouseout.js
  3894. // STARTFILE: previewmaker.js
  3895. /**
  3896.    @fileoverview
  3897.    Defines the {@link Previewmaker} object, which generates short previews from wiki markup.
  3898. */
  3899.  
  3900. /**
  3901.    Creates a new Previewmaker
  3902.    @constructor
  3903.    @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext.
  3904.    @param {String} wikiText The Wikitext source of the page we wish to preview.
  3905.    @param {String} baseUrl The url we should prepend when creating relative urls.
  3906.    @param {Navpopup} owner The navpop associated to this preview generator
  3907. */
  3908. function Previewmaker(wikiText, baseUrl, owner) {
  3909.     /** The wikitext which is manipulated to generate the preview. */
  3910.     this.originalData=wikiText;
  3911.     this.setData();
  3912.     this.baseUrl=baseUrl;
  3913.     this.owner=owner;
  3914.     this.maxCharacters=getValueOf('popupMaxPreviewCharacters');
  3915.     this.maxSentences=getValueOf('popupMaxPreviewSentences');
  3916. }
  3917. Previewmaker.prototype.setData=function() {
  3918.     var maxSize=max(10000, 2*this.maxCharacters);
  3919.     this.data=this.originalData.substring(0,maxSize);
  3920. };
  3921. /** Remove HTML comments
  3922.     @private
  3923. */
  3924. Previewmaker.prototype.killComments = function () {
  3925.     // this also kills trailing spaces and one trailing newline, eg [[diamyo]]
  3926.     this.data=this.data.replace(RegExp('<!--[\\s\\S]*?--> *\\n?', 'g'), '');
  3927. };
  3928. /**
  3929.    @private
  3930. */
  3931. Previewmaker.prototype.killDivs = function () {
  3932.     // say goodbye, divs (can be nested, so use * not *?)
  3933.     this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*?< */ *div *>',
  3934.                        'gi'), '');
  3935. };
  3936. /**
  3937.    @private
  3938. */
  3939. Previewmaker.prototype.killGalleries = function () {
  3940.     this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>',
  3941.                        'gi'), '');
  3942. };
  3943. /**
  3944.    @private
  3945. */
  3946. Previewmaker.prototype.kill = function(opening, closing, subopening, subclosing, repl) {
  3947.     var oldk=this.data;
  3948.     var k=this.killStuff(this.data, opening, closing, subopening, subclosing, repl);
  3949.     while (k.length < oldk.length) {
  3950.         oldk=k;
  3951.         k=this.killStuff(k, opening, closing, subopening, subclosing, repl);
  3952.     }
  3953.     this.data=k;
  3954. };
  3955. /**
  3956.    @private
  3957. */
  3958. Previewmaker.prototype.killStuff = function (txt, opening, closing, subopening, subclosing, repl) {
  3959.     var op=this.makeRegexp(opening);
  3960.     var cl=this.makeRegexp(closing, '^');
  3961.     var sb=subopening ? this.makeRegexp(subopening, '^') : null;
  3962.     var sc=subclosing ? this.makeRegexp(subclosing, '^') : cl;
  3963.     if (!op || !cl) {
  3964.         alert('Navigation Popups error: op or cl is null! something is wrong.');
  3965.         return;
  3966.     }
  3967.     if (!op.test(txt)) { return txt; }
  3968.     var ret='';
  3969.     var opResult = op.exec(txt);
  3970.     ret = txt.substring(0,opResult.index);
  3971.     txt=txt.substring(opResult.index+opResult[0].length);
  3972.     var depth = 1;
  3973.     while (txt.length > 0) {
  3974.         var removal=0;
  3975.         if (depth==1 && cl.test(txt)) {
  3976.             depth--;
  3977.             removal=cl.exec(txt)[0].length;
  3978.         } else if (depth > 1 && sc.test(txt)) {
  3979.             depth--;
  3980.             removal=sc.exec(txt)[0].length;
  3981.         }else if (sb && sb.test(txt)) {
  3982.             depth++;
  3983.             removal=sb.exec(txt)[0].length;
  3984.         }
  3985.         if ( !removal ) { removal = 1; }
  3986.         txt=txt.substring(removal);
  3987.         if (depth==0) { break; }
  3988.     }
  3989.     return ret + (repl || '') + txt;
  3990. };
  3991. /**
  3992.    @private
  3993. */
  3994. Previewmaker.prototype.makeRegexp = function (x, prefix, suffix) {
  3995.     prefix = prefix || '';
  3996.     suffix = suffix || '';
  3997.     var reStr='';
  3998.     var flags='';
  3999.     if (isString(x)) {
  4000.         reStr=prefix + literalizeRegex(x) + suffix;
  4001.     } else if (isRegExp(x)) {
  4002.         var s=x.toString().substring(1);
  4003.         var sp=s.split('/');
  4004.         flags=sp[sp.length-1];
  4005.         sp[sp.length-1]='';
  4006.         s=sp.join('/');
  4007.         s=s.substring(0,s.length-1);
  4008.         reStr= prefix + s + suffix;
  4009.     } else {
  4010.         log ('makeRegexp failed');
  4011.     }
  4012.  
  4013.     log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags);
  4014.     return RegExp(reStr, flags);
  4015. };
  4016. /**
  4017.    @private
  4018. */
  4019. Previewmaker.prototype.killBoxTemplates = function () {
  4020.  
  4021.     // taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general
  4022.     // also, have float_begin, ... float_end
  4023.     this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'),    /[}][}]\s*/, '{{');
  4024.  
  4025.     // infoboxes etc
  4026.     // from [[User:Zyxw/popups.js]]: kill frames too
  4027.     this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{');
  4028.  
  4029. };
  4030. /**
  4031.    @private
  4032. */
  4033. Previewmaker.prototype.killTemplates = function () {
  4034.     this.kill('{{', '}}', '{', '}', ' ');
  4035. };
  4036. /**
  4037.    @private
  4038. */
  4039. Previewmaker.prototype.killTables = function () {
  4040.     // tables are bad, too
  4041.     // this can be slow, but it's an inprovement over a browser hang
  4042.     // torture test: [[Comparison_of_Intel_Central_Processing_Units]]
  4043.     this.kill('{|', /[|]}\s*/, '{|');
  4044.     this.kill(/<table.*?>/i, /<\/table.*?>/i, /<table.*?>/i);
  4045.     // remove lines starting with a pipe for the hell of it (?)
  4046.     this.data=this.data.replace(RegExp('^[|].*$', 'mg'), '');
  4047. };
  4048. /**
  4049.    @private
  4050. */
  4051. Previewmaker.prototype.killImages = function () {
  4052.     // images and categories are a nono
  4053.     this.kill(RegExp('[[][[]\\s*(Image|File|' + pg.ns.image + '|' + pg.ns.category + ')\\s*:', 'i'),
  4054.           /\]\]\s*/, '[', ']');
  4055. };
  4056. /**
  4057.    @private
  4058. */
  4059. Previewmaker.prototype.killHTML = function () {
  4060.     // kill <ref ...>...</ref>
  4061.     this.kill(/<ref\b.*?>/i, /<\/ref>/i);
  4062.  
  4063.     // let's also delete entire lines starting with <. it's worth a try.
  4064.     this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n');
  4065.  
  4066.     // and those pesky html tags, but not <nowiki> or <blockquote>
  4067.     var splitted=this.data.parenSplit(/(<.*?>)/);
  4068.     var len=splitted.length;
  4069.     for (var i=1; i<len; i=i+2) {
  4070.         switch (splitted[i]) {
  4071.         case '<nowiki>':
  4072.         case '</nowiki>':
  4073.             break;
  4074.         default:
  4075.             if (! /^< *\/? *blockquote\b/i.test(splitted[i])) {
  4076.                 splitted[i]='';
  4077.             }
  4078.         }
  4079.     }
  4080.     this.data=splitted.join('');
  4081. };
  4082. /**
  4083.    @private
  4084. */
  4085. Previewmaker.prototype.killChunks = function() { // heuristics alert
  4086.     // chunks of italic text? you crazy, man?
  4087.     var italicChunkRegex=new RegExp
  4088.     ("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)+", 'g');
  4089.     // keep stuff separated, though, so stick in \n (fixes [[Union Jack]]?
  4090.     this.data=this.data.replace(italicChunkRegex, '\n');
  4091. };
  4092. /**
  4093.    @private
  4094. */
  4095. Previewmaker.prototype.mopup = function () {
  4096.     // we simply *can't* be doing with horizontal rules right now
  4097.     this.data=this.data.replace(RegExp('^-{4,}','mg'),'');
  4098.  
  4099.     // no indented lines
  4100.     this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '');
  4101.  
  4102.     // replace __TOC__, __NOTOC__ and whatever else there is
  4103.     // this'll probably do
  4104.     this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),'');
  4105. };
  4106. /**
  4107.    @private
  4108. */
  4109. Previewmaker.prototype.firstBit = function () {
  4110.     // dont't be givin' me no subsequent paragraphs, you hear me?
  4111.     /// first we "normalize" section headings, removing whitespace after, adding before
  4112.     var d=this.data;
  4113.  
  4114.     if (getValueOf('popupPreviewCutHeadings')) {
  4115.         this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 ');
  4116.         /// then we want to get rid of paragraph breaks whose text ends badly
  4117.         this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n');
  4118.  
  4119.         this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
  4120.         stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
  4121.         if (stuff) { d = stuff[0]; }
  4122.         if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; }
  4123.  
  4124.         /// now put \n\n after sections so that bullets and numbered lists work
  4125.         d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');
  4126.     }
  4127.  
  4128.  
  4129.     // superfluous sentences are RIGHT OUT.
  4130.     // note: exactly 1 set of parens here needed to make the slice work
  4131.     d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g'));
  4132.     // leading space is bad, mmkay?
  4133.     d[0]=d[0].replace(RegExp('^\\s*'), '');
  4134.  
  4135.     var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\[[^\\]]*|\\s[A-Zvclm])$', 'i');
  4136.     d = this.fixSentenceEnds(d, notSentenceEnds);
  4137.  
  4138.     this.fullLength=d.join('').length;
  4139.     var maxChars=getValueOf('popupMaxPreviewCharacters') + this.extraCharacters;
  4140.     var n=this.maxSentences;
  4141.     var dd=this.firstSentences(d,n); 
  4142.  
  4143.     do {
  4144.         dd=this.firstSentences(d,n); --n;
  4145.     } while ( dd.length > this.maxCharacters && n != 0 );
  4146.  
  4147.     this.data = dd;
  4148. };
  4149.  
  4150. Previewmaker.prototype.firstBit2 = function () {
  4151.     // dont't be givin' me no subsequent paragraphs, you hear me?
  4152.     /// first we "normalize" section headings, removing whitespace after, adding before
  4153.     var d=this.data;
  4154.  
  4155.     if (getValueOf('popupPreviewCutHeadings')) {
  4156.         this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 ');
  4157.         /// then we want to get rid of paragraph breaks whose text ends badly
  4158.         this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n');
  4159.  
  4160.         this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
  4161.         stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
  4162.         if (stuff) { d = stuff[0]; }
  4163.         if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; }
  4164.  
  4165.         /// now put \n\n after sections so that bullets and numbered lists work
  4166.         d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');
  4167.     }
  4168.  
  4169.  
  4170.     // superfluous sentences are RIGHT OUT.
  4171.     // note: exactly 1 set of parens here needed to make the slice work
  4172.     d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g'));
  4173.     // leading space is bad, mmkay?
  4174.     d[0]=d[0].replace(RegExp('^\\s*'), '');
  4175.  
  4176.     var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\[[^\\]]*|\\s[A-Zvclm])$', 'i');
  4177.     d = this.fixSentenceEnds(d, notSentenceEnds);
  4178.  
  4179.     this.fullLength=d.join('').length;
  4180.     var maxChars=4*(getValueOf('popupMaxPreviewCharacters') + this.extraCharacters);
  4181.     var n=4*this.maxSentences;
  4182.     var dd=this.firstSentences(d,n); 
  4183.  
  4184.     do {
  4185.         dd=this.firstSentences(d,n); --n;
  4186.     } while ( dd.length > (4*this.maxCharacters) && n != 0 );
  4187.  
  4188.     this.data = dd;
  4189. };
  4190.  
  4191. /**
  4192.    @private
  4193. */
  4194. Previewmaker.prototype.fixSentenceEnds = function(strs, reg) {
  4195.     // take an array of strings, strs
  4196.     // join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
  4197.  
  4198.     var abbrevRe=/\b[a-z][^a-z]*$/i;
  4199.  
  4200.     for (var i=0; i<strs.length-2; ++i) {
  4201.         if (reg.test(strs[i])) {
  4202.             a=[];
  4203.             for (var j=0; j<strs.length; ++j) {
  4204.                 if (j<i)   a[j]=strs[j];
  4205.                 if (j==i)  a[i]=strs[i]+strs[i+1]+strs[i+2];
  4206.                 if (j>i+2) a[j-2]=strs[j];
  4207.             }
  4208.             return this.fixSentenceEnds(a,reg);
  4209.         }
  4210.         // BUGGY STUFF - trying to fix up [[S. C. Johnson & Son]] preview
  4211.         if (false && abbrevRe.test(strs[i])) {
  4212.             var j=i, buf='';
  4213.             do {
  4214.                 buf=buf+strs[i]+strs[i+1];
  4215.                 i=i+2;
  4216.             } while (i<strs.length-2 && abbrevRe.test(strs[i]));
  4217.             strs[i]=buf+strs[i];
  4218.             var a=(j?strs.slice(0,j-1):[]).concat(strs.slice(i));
  4219.             return this.fixSentenceEnds(a,reg);
  4220.         }
  4221.     }
  4222.     return strs;
  4223. };
  4224. /**
  4225.    @private
  4226. */
  4227. Previewmaker.prototype.firstSentences = function(strs, howmany) {
  4228.     var t=strs.slice(0, 2*howmany);
  4229.     return t.join('');
  4230. };
  4231. /**
  4232.    @private
  4233. */
  4234. Previewmaker.prototype.killBadWhitespace = function() {
  4235.     // also cleans up isolated '''', eg [[Suntory Sungoliath]]
  4236.     this.data=this.data.replace(RegExp('^ *\'+ *$', 'gm'), '');
  4237. };
  4238.  
  4239. // Copyright (C) 2008 Google Inc.
  4240. //
  4241. // Licensed under the Apache License, Version 2.0 (the "License");
  4242. // you may not use this file except in compliance with the License.
  4243. // You may obtain a copy of the License at
  4244. //
  4245. //      http://www.apache.org/licenses/LICENSE-2.0
  4246. //
  4247. // Unless required by applicable law or agreed to in writing, software
  4248. // distributed under the License is distributed on an "AS IS" BASIS,
  4249. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4250. // See the License for the specific language governing permissions and
  4251. // limitations under the License.
  4252.  
  4253. /**
  4254.  * Parses a string of well-formed JSON text.
  4255.  *
  4256.  * If the input is not well-formed, then behavior is undefined, but it is
  4257.  * deterministic and is guaranteed not to modify any object other than its
  4258.  * return value.
  4259.  *
  4260.  * This does not use `eval` so is less likely to have obscure security bugs than
  4261.  * json2.js.
  4262.  * It is optimized for speed, so is much faster than json_parse.js.
  4263.  *
  4264.  * This library should be used whenever security is a concern (when JSON may
  4265.  * come from an untrusted source), speed is a concern, and erroring on malformed
  4266.  * JSON is *not* a concern.
  4267.  *
  4268.  *                      Pros                   Cons
  4269.  *                    +-----------------------+-----------------------+
  4270.  * json_sans_eval.js  | Fast, secure          | Not validating        |
  4271.  *                    +-----------------------+-----------------------+
  4272.  * json_parse.js      | Validating, secure    | Slow                  |
  4273.  *                    +-----------------------+-----------------------+
  4274.  * json2.js           | Fast, some validation | Potentially insecure  |
  4275.  *                    +-----------------------+-----------------------+
  4276.  *
  4277.  * json2.js is very fast, but potentially insecure since it calls `eval` to
  4278.  * parse JSON data, so an attacker might be able to supply strange JS that
  4279.  * looks like JSON, but that executes arbitrary javascript.
  4280.  * If you do have to use json2.js with untrusted data, make sure you keep
  4281.  * your version of json2.js so that you get patches as they're released.
  4282.  *
  4283.  * @param {string} json per RFC 4627
  4284.  * @return {Object|Array}
  4285.  * @author Mike Samuel <mikesamuel@gmail.com>
  4286.  */
  4287. var WikiLookjsonParse = (function () {
  4288.   var number
  4289.       = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)';
  4290.   var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]'
  4291.       + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
  4292.   var string = '(?:\"' + oneChar + '*\")';
  4293.  
  4294.   // Will match a value in a well-formed JSON file.
  4295.   // If the input is not well-formed, may match strangely, but not in an unsafe
  4296.   // way.
  4297.   // Since this only matches value tokens, it does not match whitespace, colons,
  4298.   // or commas.
  4299.   var jsonToken = new RegExp(
  4300.       '(?:false|true|null|[\\{\\}\\[\\]]'
  4301.       + '|' + number
  4302.       + '|' + string
  4303.       + ')', 'g');
  4304.  
  4305.   // Matches escape sequences in a string literal
  4306.   var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g');
  4307.  
  4308.   // Decodes escape sequences in object literals
  4309.   var escapes = {
  4310.     '"': '"',
  4311.     '/': '/',
  4312.     '\\': '\\',
  4313.     'b': '\b',
  4314.     'f': '\f',
  4315.     'n': '\n',
  4316.     'r': '\r',
  4317.     't': '\t'
  4318.   };
  4319.   function unescapeOne(_, ch, hex) {
  4320.     return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16));
  4321.   }
  4322.  
  4323.   // A non-falsy value that coerces to the empty string when used as a key.
  4324.   var EMPTY_STRING = new String('');
  4325.   var SLASH = '\\';
  4326.  
  4327.   // Constructor to use based on an open token.
  4328.   var firstTokenCtors = { '{': Object, '[': Array };
  4329.  
  4330.   return function (json) {
  4331.     // Split into tokens
  4332.     var toks = json.match(jsonToken);
  4333.     // Construct the object to return
  4334.     var result;
  4335.     var tok = toks[0];
  4336.     if ('{' === tok) {
  4337.       result = {};
  4338.     } else if ('[' === tok) {
  4339.       result = [];
  4340.     } else {
  4341.       throw new Error(tok);
  4342.     }
  4343.  
  4344.     // If undefined, the key in an object key/value record to use for the next
  4345.     // value parsed.
  4346.     var key;
  4347.     // Loop over remaining tokens maintaining a stack of uncompleted objects and
  4348.     // arrays.
  4349.     var stack = [result];
  4350.     for (var i = 1, n = toks.length; i < n; ++i) {
  4351.       tok = toks[i];
  4352.  
  4353.       var cont;
  4354.       switch (tok.charCodeAt(0)) {
  4355.         default:  // sign or digit
  4356.           cont = stack[0];
  4357.           cont[key || cont.length] = +(tok);
  4358.           key = void 0;
  4359.           break;
  4360.         case 0x22:  // '"'
  4361.           tok = tok.substring(1, tok.length - 1);
  4362.           if (tok.indexOf(SLASH) !== -1) {
  4363.             tok = tok.replace(escapeSequence, unescapeOne);
  4364.           }
  4365.           cont = stack[0];
  4366.           if (!key) {
  4367.             if (cont instanceof Array) {
  4368.               key = cont.length;
  4369.             } else {
  4370.               key = tok || EMPTY_STRING;  // Use as key for next value seen.
  4371.               break;
  4372.             }
  4373.           }
  4374.           cont[key] = tok;
  4375.           key = void 0;
  4376.           break;
  4377.         case 0x5b:  // '['
  4378.           cont = stack[0];
  4379.           stack.unshift(cont[key || cont.length] = []);
  4380.           key = void 0;
  4381.           break;
  4382.         case 0x5d:  // ']'
  4383.           stack.shift();
  4384.           break;
  4385.         case 0x66:  // 'f'
  4386.           cont = stack[0];
  4387.           cont[key || cont.length] = false;
  4388.           key = void 0;
  4389.           break;
  4390.         case 0x6e:  // 'n'
  4391.           cont = stack[0];
  4392.           cont[key || cont.length] = null;
  4393.           key = void 0;
  4394.           break;
  4395.         case 0x74:  // 't'
  4396.           cont = stack[0];
  4397.           cont[key || cont.length] = true;
  4398.           key = void 0;
  4399.           break;
  4400.         case 0x7b:  // '{'
  4401.           cont = stack[0];
  4402.           stack.unshift(cont[key || cont.length] = {});
  4403.           key = void 0;
  4404.           break;
  4405.         case 0x7d:  // '}'
  4406.           stack.shift();
  4407.           break;
  4408.       }
  4409.     }
  4410.     // Fail if we've got an uncompleted object.
  4411.     if (stack.length) { throw new Error(); }
  4412.     return result;
  4413.   };
  4414. })();
  4415.  
  4416.  
  4417. /////////////////////////////////////////////////////////////////////////////////////////
  4418. //JsMwApi documentation is at http://en.wiktionary.org/wiki/User_talk:Conrad.Irwin/Api.js
  4419. /////////////////////////////////////////////////////////////////////////////////////////
  4420. function JsMwApi (api_url, request_type) {
  4421.  
  4422.     if (!api_url) 
  4423.     {
  4424.         if (typeof(wgEnableAPI) === 'undefined' || wgEnableAPI == false)
  4425.             throw "Local API is not usable.";
  4426.  
  4427.         api_url = wgScriptPath + "/api.php";
  4428.     }
  4429.  
  4430.     if (!request_type)
  4431.     {
  4432.         if (api_url.indexOf('http://') == 0 || api_url.indexOf('https://') == 0)
  4433.             request_type = "remote";
  4434.         else
  4435.             request_type = "local";
  4436.     }
  4437.     function call_api (query, callback)
  4438.     {
  4439.         if(!query || !callback)
  4440.             throw "Insufficient parameters for API call";
  4441.  
  4442.         query = serialise_query(query);
  4443.  
  4444.         if(request_type == "remote")
  4445.             request_remote(api_url, query, callback, call_api.on_error || default_on_error);
  4446.         else
  4447.             request_local(api_url, query, callback, call_api.on_error || default_on_error);
  4448.  
  4449.     }
  4450.  
  4451.     var default_on_error = JsMwApi.prototype.on_error || function (xhr, callback, res)
  4452.     {
  4453.         if (typeof(console) != 'undefined')
  4454.             console.log([xhr, res]);
  4455.  
  4456.         callback(null);
  4457.     }
  4458.  
  4459.     function get_xhr () 
  4460.     {
  4461.         try{
  4462.             return new XMLHttpRequest();
  4463.         }catch(e){ try {
  4464.             return new ActiveXObject("Msxml2.XMLHTTP");
  4465.         }catch(e){ try {
  4466.             return new ActiveXObject("Microsoft.XMLHTTP");
  4467.         }catch(e){
  4468.             throw "Could not create an XmlHttpRequest";
  4469.         }}}
  4470.     }
  4471.  
  4472.     function request_local (url, query, callback, on_error)
  4473.     {
  4474.         var xhr = get_xhr();
  4475.  
  4476.         xhr.open('POST', url + '?format=json', true);
  4477.         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");                  
  4478.         xhr.send(query);
  4479.         xhr.onreadystatechange = function ()
  4480.         {
  4481.             if (xhr.readyState == 4)
  4482.             {
  4483.                 var res;
  4484.                 if (xhr.status != 200)
  4485.                     res = {error: {
  4486.                         code: '_badresponse', 
  4487.                         info: xhr.status + " " + xhr.statusText
  4488.                     }};
  4489.                 else
  4490.                 {
  4491.                     try
  4492.                     {
  4493.                         res = JSON.parse("("+xhr.responseText+")");
  4494.                     }
  4495.                     catch(e)
  4496.                     {
  4497.                         res = {error: {
  4498.                             code: '_badresult',
  4499.                             info: "The server returned an incorrectly formatted response"
  4500.                         }};
  4501.                     }
  4502.                 }
  4503.                 if (!res || res.error || res.warnings)
  4504.                     on_error(xhr, callback, res);
  4505.                 else
  4506.                     callback(res);
  4507.             }
  4508.         }
  4509.     }
  4510.  
  4511.     function request_remote (url, query, callback, on_error)
  4512.     {
  4513.         if(! window.__JsMwApi__counter)
  4514.             window.__JsMwApi__counter = 0;
  4515.  
  4516.         var cbname = '__JsMwApi__callback' + window.__JsMwApi__counter++; 
  4517.  
  4518.         window[cbname] = function (res)
  4519.         {
  4520.             if (res.error || res.warnings)
  4521.                 on_error(null, callback, res);
  4522.             else
  4523.                 callback(res);
  4524.         }
  4525.  
  4526.         var script = document.createElement('script');
  4527.         script.setAttribute('type', 'text/javascript');
  4528.         script.setAttribute('src', url + '?format=json&callback=window.' + cbname + '&' + query);
  4529.         document.getElementsByTagName('head')[0].appendChild(script);
  4530.     }
  4531.  
  4532.     function serialise_query (obj)
  4533.     {
  4534.         var amp = "";
  4535.         var out = "";
  4536.         if (String(obj) === obj)
  4537.         {
  4538.             out = obj;
  4539.         }
  4540.         else if (obj instanceof Array)
  4541.         {
  4542.             for (var i=0; i < obj.length; i++)
  4543.             {
  4544.                 out += amp + serialise_query(obj[i]);
  4545.                 amp = (out == '' || out.charAt(out.length-1) == '&') ? '' : '&';
  4546.             }
  4547.         }
  4548.         else if (obj instanceof Object)
  4549.         {
  4550.             for (var k in obj)
  4551.             {
  4552.                 if (obj[k] === true)
  4553.                     out += amp + encodeURIComponent(k) + '=1';
  4554.                 else if (obj[k] === false)
  4555.                     continue;
  4556.                 else if (obj[k] instanceof Array)
  4557.                     out += amp + encodeURIComponent(k) + '=' + encodeURIComponent(obj[k].join('|'));
  4558.                 else if (obj[k] instanceof Object)
  4559.                     throw "API parameters may not be objects";
  4560.                 else
  4561.                     out += amp + encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]);
  4562.                 amp = '&';
  4563.             }
  4564.         }
  4565.         else if (typeof(obj) !== 'undefined' && obj !== null)
  4566.         {
  4567.             throw "An API query can only be a string or an object";
  4568.         }
  4569.         return out;
  4570.     }
  4571.  
  4572.     // Make JSON.parse work
  4573.     var JSON = (typeof JSON == 'undefined' ? new Object() : JSON);
  4574.  
  4575.     if (typeof JSON.parse != 'function')
  4576.         JSON.parse = function (json) { return WikiLookjsonParse('(' + json + ')'); }; 
  4577.  
  4578.     // Allow .prototype. extensions
  4579.     if (JsMwApi.prototype)
  4580.     {
  4581.         for (var i in JsMwApi.prototype)
  4582.         {
  4583.             call_api[i] = JsMwApi.prototype[i];
  4584.         }
  4585.     }
  4586.     return call_api;
  4587. }
  4588.  
  4589. JsMwApi.prototype.page = function (title) {
  4590.  
  4591.     function call_with_page (params, callback)
  4592.     {
  4593.         call_with_page.api([params, {title: title, titles: title}], callback);
  4594.     }
  4595.  
  4596.     call_with_page.api = this;
  4597.  
  4598.     call_with_page.edit = function (params, edit_function)
  4599.     {
  4600.         if (typeof(params) == 'function')
  4601.         {
  4602.             edit_function = params;
  4603.             params = null;
  4604.         }
  4605.         params = [params, {
  4606.             action: "query", 
  4607.             prop: ["info", "revisions"], 
  4608.             intoken: "edit", 
  4609.             rvprop: ["content", "timestamp"]
  4610.         }];
  4611.  
  4612.         call_with_page(params, function (res)
  4613.         {
  4614.             if (!res || !res.query || !res.query.pages)
  4615.                 return edit_function(null);
  4616.  
  4617.             // Get the first (and only) page from res.query.pages
  4618.             for (var pageid in res.query.pages) break;
  4619.             var page = res.query.pages[pageid];
  4620.  
  4621.             var text = page.revisions ? page.revisions[0]['*'] : '';
  4622.  
  4623.             function save_function (ntext, params, post_save)
  4624.             {
  4625.                 if (typeof(params) == 'function')
  4626.                 {
  4627.                     post_save = params;
  4628.                     params = null;
  4629.                 }
  4630.                 params = [params, {
  4631.                     action: "edit",
  4632.                     text: ntext,
  4633.                     token: page.edittoken,
  4634.                     starttimestamp: page.starttimestamp,
  4635.                     basetimestamp: (page.revisions ? page.revisions[0].timestamp : false)
  4636.                 }];
  4637.  
  4638.                 call_with_page(params, post_save);
  4639.             }
  4640.  
  4641.             edit_function(text, save_function, res);
  4642.  
  4643.         });
  4644.     }
  4645.  
  4646.     call_with_page.parse = function (to_parse, callback)
  4647.     {
  4648.         if (typeof to_parse == "function")
  4649.         {
  4650.             callback = to_parse;
  4651.             to_parse = null;
  4652.         }
  4653.         var params = (to_parse == null ? {page: title} : {title: title, text: to_parse});
  4654.  
  4655.         call_with_page.api([{action: "parse", pst: true}, params], function (res)
  4656.         //call_with_page.api([{action: "expandtemplates", pst: true}, params], function (res)
  4657.         {
  4658.             if (!res || !res.parse || !res.parse.text)
  4659.                 callback(null, res);
  4660.             else
  4661.                 callback(res.parse.text['*'], res);
  4662.         })
  4663.     }
  4664.  
  4665.     call_with_page.parseFragment = function (to_parse, callback)
  4666.     {
  4667.         call_with_page.parse("<div>\n" + to_parse + "</div>", function (parsed, res)
  4668.         {
  4669.             callback(parsed ? parsed.replace(/^<div>\n?/,'').replace(/(\s*\n)?<\/div>\n*(<!--[^>]*-->\s*)?$/,'') : parsed, res);
  4670.         })
  4671.     }
  4672.  
  4673.     return call_with_page;
  4674. }
  4675.  
  4676.  
  4677.  function expandWikiTextPreview(wt) {
  4678.     if (pg.wiki.hostname=="en.wikipedia.org") { wt=wt.replace(/\|(\s*?)Img(\s*?)=/gi , "| Image ="); }
  4679.     if (pg.wiki.hostname=="de.wikipedia.org") { wt=wt.replace(/\[\[\Datei:/g , "[[Bild:");    }
  4680.     if (pg.wiki.hostname=="ru.wikipedia.org") { wt=wt.replace(/\[\[\╨ñ╨░╨╣╨╗:/g , "[[╨ÿ╨╖╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╕╨╡:"); }
  4681.     if (pg.wiki.hostname=="it.wikipedia.org") { wt=wt.replace(/\[\[\Immagine:/g , "[[File:");    }
  4682.     if (pg.wiki.hostname=="es.wikipedia.org") { wt=wt.replace(/\[\[\Archivo:/g , "[[Imagen:");    }
  4683.     if (pg.wiki.hostname=="pt.wikipedia.org") { wt=wt.replace(/\[\[\Ficheiro:/g , "[[Imagem:");    }
  4684.     if (pg.wiki.hostname=="fr.wikipedia.org") { wt=wt.replace(/\[\[\Fichier:/g , "[[Image:");
  4685.         wt=wt.replace(/\[\[\File:/g , "[[Image:"); }
  4686.     if (pg.wiki.hostname=="sv.wikipedia.org") { wt=wt.replace(/\[\[\Fil:/g , "[[Bild:"); 
  4687.         wt=wt.replace(/\[\[\File:/g , "[[Bild:"); }
  4688.     if (pg.wiki.hostname=="uk.wikipedia.org") { wt=wt.replace(/\[\[\╨ñ╨░╨╣╨╗:/g , "[[╨ù╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╜╤Å:");    }
  4689.     if (pg.wiki.hostname=="ca.wikipedia.org") {    wt=wt.replace(/\[\[\Fitxer:/g , "[[Imatge:"); }
  4690.     if (pg.wiki.hostname=="cs.wikipedia.org") { wt=wt.replace(/\[\[\File:/g , "[[Soubor:");    }
  4691.     if (pg.wiki.hostname=="da.wikipedia.org") { wt=wt.replace(/\[\[\Fil:/g , "[[Billede:");    }
  4692. //    if (pg.wiki.hostname=="id.wikipedia.org") { wt=wt.replace(/\[\[\Berkas:/g , "[[Image:"); }
  4693.     if (pg.wiki.hostname=="ja.wikipedia.org") { wt=wt.replace(/\[\[\πâòπéíπéñπâ½:/g , "[[τö╗σâÅ:");    }
  4694.     if (pg.wiki.hostname=="nl.wikipedia.org") { wt=wt.replace(/\[\[\Bestand:/g , "[[Afbeelding:"); }
  4695.     if (pg.wiki.hostname=="ko.wikipedia.org") { wt=wt.replace(/\[\[\φîî∞¥╝:/g , "[[Ω╖╕δª╝:"); }    
  4696.     if (pg.wiki.hostname=="no.wikipedia.org") { wt=wt.replace(/\[\[\Fil:/g , "[[Bilde:"); }
  4697.     if (pg.wiki.hostname=="ro.wikipedia.org") { wt=wt.replace(/\[\[\Fi┼ƒier:/g , "[[Imagine:");}
  4698.     if (pg.wiki.hostname=="sk.wikipedia.org") { wt=wt.replace(/\[\[\File:/g , "[[Obr├ízok:"); }
  4699.     if (pg.wiki.hostname=="fi.wikipedia.org") { wt=wt.replace(/\[\[\Tiedosto:/g , "[[Kuva:"); }
  4700.     if (pg.wiki.hostname=="hu.wikipedia.org") { wt=wt.replace(/\[\[\F├íjl:/g , "[[K├⌐p:"); }
  4701.     if (pg.wiki.hostname=="tr.wikipedia.org") { wt=wt.replace(/\[\[\Dosya:/g , "[[Resim:"); }
  4702.     if (pg.wiki.hostname=="vi.wikipedia.org") { wt=wt.replace(/\[\[\Tß║¡p tin:/g , "[[H├¼nh:"); }
  4703.     if (pg.wiki.hostname=="sw.wikipedia.org") { wt=wt.replace(/\[\[\picha:/g , "[[File:"); }
  4704. //    if (pg.wiki.hostname=="ar.wikipedia.org") { wt=wt.replace(/\[\[\┘à┘ä┘ü:/g , "[[:╪╡┘ê╪▒╪⌐"); }
  4705.  
  4706.     
  4707.     return wt;
  4708. }
  4709.  
  4710. Previewmaker.prototype.expandWikiText = function() {
  4711.  
  4712.     
  4713.     this.data=this.data.replace(/\((.*?)\{\{(.*?)\}\}(.*?)\)/g, "");
  4714.     this.data=this.data.replace(/\<ref name(.*?)\<\/ref\>/g, "");
  4715.     this.data=this.data.replace(/\*?\*?\:?\s?{{(also|rank|wikipedia|trans-top|mid2|mid3|mid4|checktrans-top|trans-bottom|trans-mid)\|?(.*?)}}/g ,""); /*audio|rhymes|hyphenation|*/
  4716.     this.data=this.data.replace(/{{a\|(.*?)}}/g ,"($1)");
  4717.  
  4718.     this.data=this.data.replace(/{{t(\+|\-|\├╕|)\|(.*?)\|(.*?)(\|.*?)?}}/g ,"$3");
  4719.     this.data=this.data.replace(/{{lang(\+|\-|\├╕|)\|(.*?)\|(.*?)(\|.*?)?}}/g ,"$3");
  4720.  
  4721.     this.data=this.data.replace(/\[[0-9]?\,?[0-9]?\]/g ,"");
  4722.     this.data=this.data.replace(/\*\:?\s?,?\s?.?\s?,?\s?\n/, "");
  4723.     
  4724.     
  4725.     if (pg.wiki.hostname=="en.wikipedia.org") { 
  4726.         this.data=this.data.replace(/\|(\s*?)Img(\s*?)=/gi , "| Image ="); 
  4727.         this.data=this.data.replace(/\|(\s*?)map(\s*?)=/gi , "| Image =");
  4728.     }
  4729.     if (pg.wiki.hostname=="de.wikipedia.org") { this.data=this.data.replace(/\[\[\Datei:/g , "[[Bild:"); }
  4730.     if (pg.wiki.hostname=="ru.wikipedia.org") { this.data=this.data.replace(/\[\[\╨ñ╨░╨╣╨╗:/g , "[[╨ÿ╨╖╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╕╨╡:");    }
  4731.     if (pg.wiki.hostname=="it.wikipedia.org") { this.data=this.data.replace(/\[\[\Immagine:/g , "[[File:");    }
  4732.     if (pg.wiki.hostname=="es.wikipedia.org") { this.data=this.data.replace(/\[\[\Archivo:/g , "[[Imagen:"); }
  4733.     if (pg.wiki.hostname=="pt.wikipedia.org") { this.data=this.data.replace(/\[\[\Ficheiro:/g , "[[Imagem:"); }
  4734.     if (pg.wiki.hostname=="fr.wikipedia.org") { this.data=this.data.replace(/\[\[\Fichier:/g , "[[Image:");    
  4735.         this.data=this.data.replace(/\[\[\File:/g , "[[Image:");    }
  4736.     if (pg.wiki.hostname=="sv.wikipedia.org") { this.data=this.data.replace(/\[\[\Fil:/g , "[[Bild:"); 
  4737.         this.data=this.data.replace(/\[\[\File:/g , "[[Bild:"); }
  4738.     if (pg.wiki.hostname=="uk.wikipedia.org") { this.data=this.data.replace(/\[\[\╨ñ╨░╨╣╨╗:/g , "[[╨ù╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╜╤Å:"); }
  4739.     if (pg.wiki.hostname=="ca.wikipedia.org") { this.data=this.data.replace(/\[\[\Fitxer:/g , "[[Imatge:");    }
  4740.     if (pg.wiki.hostname=="cs.wikipedia.org") { this.data=this.data.replace(/\[\[\File:/g , "[[Soubor:"); }
  4741.     if (pg.wiki.hostname=="da.wikipedia.org") { this.data=this.data.replace(/\[\[\Fil:/g , "[[Billede:"); }    
  4742. //    if (pg.wiki.hostname=="id.wikipedia.org") { this.data=this.data.replace(/\[\[\Berkas:/g , "[[Image:");    }
  4743.     if (pg.wiki.hostname=="ja.wikipedia.org") { this.data=this.data.replace(/\[\[\πâòπéíπéñπâ½:/g , "[[τö╗σâÅ:"); }
  4744.     if (pg.wiki.hostname=="nl.wikipedia.org") { this.data=this.data.replace(/\[\[\Bestand:/g , "[[Afbeelding:"); }
  4745.     if (pg.wiki.hostname=="ko.wikipedia.org") { this.data=this.data.replace(/\[\[\φîî∞¥╝:/g , "[[Ω╖╕δª╝:");    }
  4746.     if (pg.wiki.hostname=="no.wikipedia.org") { this.data=this.data.replace(/\[\[\Fil:/g , "[[Bilde:");    }
  4747.     if (pg.wiki.hostname=="ro.wikipedia.org") { this.data=this.data.replace(/\[\[\Fi┼ƒier:/g , "[[Imagine:");    }
  4748.     if (pg.wiki.hostname=="sk.wikipedia.org") { this.data=this.data.replace(/\[\[\File:/g , "[[Obr├ízok:");    }
  4749.     if (pg.wiki.hostname=="fi.wikipedia.org") { this.data=this.data.replace(/\[\[\Tiedosto:/g , "[[Kuva:"); }
  4750.     if (pg.wiki.hostname=="hu.wikipedia.org") { this.data=this.data.replace(/\[\[\F├íjl:/g , "[[K├⌐p:"); }
  4751.     if (pg.wiki.hostname=="tr.wikipedia.org") { this.data=this.data.replace(/\[\[\Dosya:/g , "[[Resim:"); }
  4752.     if (pg.wiki.hostname=="vi.wikipedia.org") { this.data=this.data.replace(/\[\[\Tß║¡p tin:/g , "[[H├¼nh:"); }
  4753.     if (pg.wiki.hostname=="sw.wikipedia.org") { this.data=this.data.replace(/\[\[\picha:/g , "[[File:"); }
  4754. //    if (pg.wiki.hostname=="ar.wikipedia.org") { this.data=this.data.replace(/\[\[\┘à┘ä┘ü:/g , "[[:╪╡┘ê╪▒╪⌐"); }
  4755.     if (pg.wiki.hostname.indexOf("wiktionary")!=-1) {
  4756.         WikiLook_Overlay.PMaker=this;
  4757.         var localApi = JsMwApi("http://" + pg.wiki.hostname + "/w/api.php", "local");
  4758.         localApi({action: 'expandtemplates', text:this.data, title:WikiLook_Overlay._currentWord}, function (res) { 
  4759.         WikiLook_Overlay.PMaker.WLWTajaxCallbackImpl(res.expandtemplates.*); 
  4760.         });
  4761.     } else {
  4762.         this.makePreview2();
  4763.     }
  4764. }
  4765.  
  4766. Previewmaker.prototype.WLWTajaxCallbackImpl = function(res) {
  4767.     if (WikiLook_Overlay.PMakerFlag==true){WikiLook_Overlay.PMakerFlag=false; return}
  4768.     //alert(res.substring(0,1700));
  4769.     this.data=res;
  4770.     //this.makePreview2();
  4771.     this.data=this.data.replace(/\|(\s*?),/gi , ",");
  4772.  
  4773.     
  4774.     if (pg.wiki.hostname=="fr.wiktionary.org") { 
  4775.         this.data=this.data.replace(/\<h3(.*?)\>/ig, '<wikilookh3>'); 
  4776.         this.data=this.data.replace(/\<\\h3\>/ig, '<\wikilookh3>'); 
  4777.         
  4778.         this.data=this.data.replace(/\[\[\Image\:\Nuvola apps bookcase\.svg\|30px\|link\=(.*?)\]\]/ig, '<a href="http://fr.wiktionary.org/wiki/Aide:%C3%89tymologies" title="Origine et histoire de ┬½ bienvenue ┬╗"><img alt="Origine et histoire de ┬½ bienvenue ┬╗" src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Nuvola_apps_bookcase.svg/30px-Nuvola_apps_bookcase.svg.png" width="30" height="30" /></a>'); 
  4779.         this.data=this.data.replace(/\[\[\Image\:\Open book 01\.svg\|30px\|link\=\Aide\:\Types de mots\]\]/ig , '<a href="http://fr.wiktionary.org/wiki/Aide:Types_de_mots" title="Aide:Types de mots"><img alt="Open book 01.svg" src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Open_book_01.svg/30px-Open_book_01.svg.png" width="30" height="30" /></a>'); 
  4780.         this.data=this.data.replace(/\[\[Image\:\Nuvola apps edu languages\.svg\|30px\|link\=\Annexe\:\Prononciation\]\]/ig , '<a href="http://fr.wiktionary.org/wiki/Annexe:Prononciation" title="Annexe:Prononciation"><img alt="Nuvola apps edu languages.svg" src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Nuvola_apps_edu_languages.svg/30px-Nuvola_apps_edu_languages.svg.png" width="30" height="30" /></a>'); 
  4781.         this.data=this.data.replace('[[File:Books-aj.svg aj ashton 01f.svg|35px|link=Wiktionnaire:R├⌐f├⌐rences]]' , '<a href="http://fr.wiktionary.org/wiki/Wiktionnaire:R%C3%A9f%C3%A9rences" title="Wiktionnaire:R├⌐f├⌐rences"><img alt="Books-aj.svg aj ashton 01f.svg" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Books-aj.svg_aj_ashton_01f.svg/35px-Books-aj.svg_aj_ashton_01f.svg.png" width="35" height="31" /></a>'); 
  4782.         
  4783.     }
  4784.     
  4785.         
  4786.     this.killChunks();
  4787.     this.mopup();
  4788.     this.firstBit2();
  4789.     this.killBadWhitespace();
  4790.     this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
  4791.     this.fixHTML();
  4792.     this.stripLongTemplates();
  4793.  
  4794.     this.data=this.data.replace(/\<p\\>/gi , "");
  4795.     
  4796.     this.showPreview();
  4797.     WikiLook_Overlay.PMakerFlag=true;
  4798. }
  4799. /**
  4800.    Runs the various methods to generate the preview.
  4801.    The preview is stored in the <code>html</html> field.
  4802.    @private
  4803. */
  4804.  
  4805. Previewmaker.prototype.makePreview = function() {
  4806.     if (this.owner.article.namespace()!=pg.ns.template &&
  4807.                 this.owner.article.namespace()!=pg.ns.image ) {
  4808.         this.expandWikiText();
  4809.     }
  4810.     else
  4811.     {
  4812.         this.killHTML();
  4813.         this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
  4814.         this.fixHTML();
  4815.         this.stripLongTemplates();
  4816.  
  4817.     }
  4818. };
  4819.  
  4820. Previewmaker.prototype.makePreview2 = function() {
  4821.         this.killComments();
  4822.         this.killDivs();
  4823.         this.killGalleries();
  4824.         this.killBoxTemplates();
  4825.         
  4826.         if (getValueOf('popupPreviewKillTemplates') /*&& (pg.wiki.hostname.indexOf("wiktionary")==-1)*/) { //for testing templates on Wiktionarys
  4827.             this.killTemplates();
  4828.         } else {
  4829.             this.killMultilineTemplates();
  4830.         }
  4831.         
  4832.         this.killTables();
  4833.         this.killImages();
  4834.         this.killHTML();
  4835.         this.killChunks();
  4836.         this.mopup();
  4837.  
  4838.         this.firstBit();
  4839.         this.killBadWhitespace();
  4840.         
  4841.         this.html=wiki2html(this.data, this.baseUrl); // needs livepreview
  4842.         this.fixHTML();
  4843.         this.stripLongTemplates();
  4844.  
  4845. };
  4846.  
  4847.  
  4848.  
  4849. /**
  4850.    @private
  4851. */
  4852. Previewmaker.prototype.esWiki2HtmlPart = function(data) {
  4853.   var reLinks = /(?:\[\[([^|\]]*)(?:\|([^|\]]*))*]]([a-z]*))/gi; //match a wikilink
  4854.   reLinks.lastIndex = 0; //reset regex
  4855.  
  4856.   var match;
  4857.   var result = "";
  4858.   var postfixIndex = 0;
  4859.   while ((match = reLinks.exec(data)) != null) //match all wikilinks
  4860.   {
  4861.     //FIXME: the way that link is built here isn't perfect. It is clickable, but popups preview won't recognize it in some cases.
  4862.     result += escapeQuotesHTML(data.substring(postfixIndex, match.index)) + 
  4863.               "<a href='"+Insta.conf.paths.articles+match[1]+"'>"+escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>";
  4864.     postfixIndex = reLinks.lastIndex;
  4865.   }
  4866.   //append the rest
  4867.   result += escapeQuotesHTML(data.substring(postfixIndex));
  4868.   
  4869.   return result;
  4870. };
  4871. Previewmaker.prototype.editSummaryPreview=function() {
  4872.     var reAes   = /\/\* *(.*?) *\*\//g; //match the first section marker
  4873.     reAes.lastIndex = 0; //reset regex
  4874.     
  4875.     var match;
  4876.     
  4877.     match = reAes.exec(this.data);
  4878.     if (match)
  4879.     {
  4880.         //we have a section link. Split it, process it, combine it.
  4881.         var prefix = this.data.substring(0,match.index-1);
  4882.         var section = match[1];
  4883.         var postfix = this.data.substring(reAes.lastIndex);
  4884.         
  4885.         var start = "<span class='autocomment'>";
  4886.         var end = "</span>";
  4887.         if (prefix.length>0) start = this.esWiki2HtmlPart(prefix) + " " + start + "- ";
  4888.         if (postfix.length>0) end = ": " + end + this.esWiki2HtmlPart(postfix);
  4889.         
  4890.  
  4891.         var t=new Title().fromURL(this.baseUrl);
  4892.         t.anchorFromUtf(section);
  4893.         var sectionLink = Insta.conf.paths.articles + t.toString(true).split("'").join('%27') + '#' + t.anchor.split("'").join('%27');
  4894.         return start + "<a href='"+sectionLink+"'>→</a> "+escapeQuotesHTML(section) + end;
  4895.     }
  4896.     
  4897.     //else there's no section link, htmlify the whole thing.
  4898.     return this.esWiki2HtmlPart(this.data);
  4899. };
  4900.  
  4901. //<NOLITE>
  4902. /** Test function for debugging preview problems one step at a time.
  4903.  */
  4904. function previewSteps(txt) {
  4905.     try {
  4906.         txt=txt || document.editform.wpTextbox1.value;
  4907.     } catch (err) {
  4908.         if (pg.cache.pages.length > 0) {
  4909.             txt=pg.cache.pages[pg.cache.pages.length-1].data;
  4910.         } else {
  4911.             alert('provide text or use an edit page');
  4912.         }
  4913.     }
  4914.     txt=txt.substring(0,10000);
  4915.     var base=pg.wiki.articlebase + Title.fromURL(document.location.href).urlString();
  4916.     var p=new Previewmaker(txt, base, pg.current.link.navpopup);
  4917.     if (this.owner.article.namespace() != pg.ns.template) {
  4918.         p.killComments(); if (!confirm('done killComments(). Continue?\n---\n' + p.data)) { return; }
  4919.         p.killDivs(); if (!confirm('done killDivs(). Continue?\n---\n' + p.data)) { return; }
  4920.         p.killGalleries(); if (!confirm('done killGalleries(). Continue?\n---\n' + p.data)) { return; }
  4921.         p.killBoxTemplates(); if (!confirm('done killBoxTemplates(). Continue?\n---\n' + p.data)) { return; }
  4922.  
  4923.         if (getValueOf('popupPreviewKillTemplates')) {
  4924.             p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; }
  4925.         } else {
  4926.             p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; }
  4927.         }
  4928.  
  4929.         p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; }
  4930.         p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; }
  4931.         p.killHTML(); if (!confirm('done killHTML(). Continue?\n---\n' + p.data)) { return; }
  4932.         p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; }
  4933.         p.mopup(); if (!confirm('done mopup(). Continue?\n---\n' + p.data)) { return; }
  4934.  
  4935.         p.firstBit(); if (!confirm('done firstBit(). Continue?\n---\n' + p.data)) { return; }
  4936.         p.killBadWhitespace(); if (!confirm('done killBadWhitespace(). Continue?\n---\n' + p.data)) { return; }
  4937.     }
  4938.  
  4939.     p.html=wiki2html(p.data, base); // needs livepreview
  4940.     p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; }
  4941.     p.stripLongTemplates(); if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { return; }
  4942.     alert('finished preview - end result follows.\n---\n' + p.html);
  4943. }
  4944. //</NOLITE>
  4945.  
  4946. /**
  4947.    Works around a quoting bug in livepreview.
  4948.    <code>wiki2html('[[Foo\'s "bar"]]')</code> gives @literal{<a href='Foo's "bar"'>}
  4949.    which doesn't do very well. We change this into @literal{<a href="Foo's %22bar%22">}
  4950.    @private
  4951. */
  4952. Previewmaker.prototype.fixHTML = function() {
  4953.     if(!this.html) return;
  4954.     // all links seem to have potential issues with quotation marks
  4955.     var splitted=this.html.parenSplit(/href='([^>]*)'/g);
  4956.     var ret='';
  4957.     for (var i=0; i<splitted.length; ++i) {
  4958.         if(i%2==0) { ret += splitted[i]; continue; }
  4959.         if(i%2==1) { ret += 'href="' + splitted[i].split('"').join('%22') + '"'; }
  4960.     }
  4961.     // fix question marks in wiki links
  4962.     // maybe this'll break some stuff :-(
  4963.     ret=ret.replace(RegExp('\(<a href="/' + pg.wiki.articlePath + '/[^"]*\)[?]\(.*?"\)', 'g'), '$1%3F$2');
  4964.     ret=ret.replace("a href=\"", "a href=\""+ WikiLook_Overlay._currentParser,"gi");
  4965.     // FIXME fix up % too
  4966.     this.html=ret;
  4967. };
  4968. /**
  4969.    Generates the preview and displays it in the current popup.
  4970.  
  4971.    Does nothing if the generated preview is invalid or consists of whitespace only.
  4972.    Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true.
  4973. */
  4974. Previewmaker.prototype.showPreview = function () {
  4975.     this.makePreview();
  4976.     if (typeof this.html != typeof '') return;
  4977.     if (RegExp('^\\s*$').test(this.html)) return;
  4978.     setPopupHTML('<hr>', 'popupPrePreviewSep', this.owner.idNumber);
  4979.     setPopupTipsAndHTML(this.html, 'popupPreview', this.owner.idNumber, { owner: this.owner });
  4980.     var more = (this.fullLength > this.data.length) ? this.moreLink() : '';
  4981.     setPopupHTML(more, 'popupPreviewMore', this.owner.idNumber);
  4982.  
  4983. };
  4984. /**
  4985.    @private
  4986. */
  4987. Previewmaker.prototype.moreLink=function() {
  4988.     var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  4989.     a.className='popupMoreLink';
  4990.     a.innerHTML=popupString('more...');
  4991.     var savedThis=this;
  4992.     a.onclick=function() {
  4993.         savedThis.maxCharacters+=2000;
  4994.         savedThis.maxSentences+=20;
  4995.         savedThis.setData();
  4996.         savedThis.showPreview();
  4997.     }
  4998.     return a;
  4999. }
  5000.  
  5001. /**
  5002.    @private
  5003. */
  5004. Previewmaker.prototype.stripLongTemplates = function() {
  5005.     // operates on the HTML!
  5006.     this.html=this.html.replace(RegExp('^.{0,1000}[{][{][^}]*?(<(p|br)( /)?>\\s*){2,}([^{}]*?[}][}])?', 'gi'), '');
  5007.     this.html=this.html.split('\n').join(' '); // workaround for <pre> templates
  5008.     this.html=this.html.replace(RegExp('[{][{][^}]*<pre>[^}]*[}][}]','gi'), '');
  5009. };
  5010. /**
  5011.    @private
  5012. */
  5013. Previewmaker.prototype.killMultilineTemplates = function() {
  5014.     this.kill('{{{', '}}}');
  5015.     this.kill(RegExp('\\s*[{][{][^{}]*\\n'), '}}', '{{');
  5016. };
  5017. // ENDFILE: previewmaker.js
  5018. // STARTFILE: querypreview.js
  5019. function loadAPIPreview(queryType, article, navpop) {
  5020.     var art=new Title(article).urlString();
  5021.     var url=pg.wiki.wikibase + '/api.php?format=json&action=query&';
  5022.     var htmlGenerator=function(a,d){alert('invalid html generator');};
  5023.     switch (queryType) {
  5024.     case 'history':
  5025.         url += 'meta=userinfo&uiprop=options&titles=' + art + '&prop=revisions&rvlimit=' +
  5026.             getValueOf('popupHistoryPreviewLimit');
  5027.         htmlGenerator=APIhistoryPreviewHTML;
  5028.         break;
  5029.     case 'category':
  5030.         url += 'list=categorymembers&cmtitle=' + art;
  5031.         htmlGenerator=APIcategoryPreviewHTML;
  5032.         break;
  5033.     case 'userinfo':
  5034.         var usernameart = encodeURIComponent( new Title( article ).userName() );
  5035.         url += 'list=users&usprop=blockinfo|groups|editcount|registration&ususers=' + usernameart;
  5036.         htmlGenerator=APIuserInfoPreviewHTML;
  5037.         break;
  5038.     case 'contribs':
  5039.         var usernameart = encodeURIComponent( new Title( article ).userName() );
  5040.         url += 'list=usercontribs&meta=userinfo&uiprop=options&ucuser=' + usernameart +
  5041.             '&uclimit=' + getValueOf('popupContribsPreviewLimit');
  5042.         htmlGenerator=APIcontribsPreviewHTML;
  5043.         break;
  5044.     case 'imagepagepreview':
  5045.         var trail='';
  5046.         if (getValueOf('popupImageLinks')) { trail = '&list=imageusage&iutitle=' + art; }
  5047.         url += 'titles=' + art + '&prop=revisions|imageinfo&rvprop=content' + trail;
  5048.         htmlGenerator=APIimagepagePreviewHTML;
  5049.         break;
  5050.     case 'backlinks':
  5051.         url += 'list=backlinks&bltitle=' + art;
  5052.         htmlGenerator=APIbacklinksPreviewHTML;
  5053.         break;
  5054.     }
  5055.     pendingNavpopTask(navpop);
  5056.     if( !window.wgEnableAPI || !wgEnableAPI ) {
  5057.         /* The API is not available */
  5058.         htmlGenerator=function(a,d){
  5059.             return ''; };
  5060.     }
  5061.     var callback=function(d){
  5062.         log( "callback of API functions was hit" );
  5063.         showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
  5064.     };
  5065.     var go = function(){
  5066.         getPageWithCaching(url, callback, navpop);
  5067.         return true;
  5068.     }
  5069.     if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); }
  5070.     else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); }
  5071. }
  5072.  
  5073. function linkList(list) {
  5074.     list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); });
  5075.     var buf=[];
  5076.     for (var i=0; i<list.length; ++i) {
  5077.         buf.push(wikiLink({article: new Title(list[i]),
  5078.                    text:    list[i].split(' ').join(' '),
  5079.                    action:  'view'}));
  5080.     }
  5081.     return buf.join(', ');
  5082. }
  5083.  
  5084. function getTimeOffset(tz) {
  5085.     if( tz ) {
  5086.         if( tz.indexOf('|') > -1 ) {
  5087.             // New format
  5088.             return parseInt(tz.split('|')[1],10);
  5089.         } else if ( tz.indexOf(':') > -1 ) {
  5090.             // Old format
  5091.             return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) );
  5092.         }
  5093.     }
  5094.     return 0;
  5095. }
  5096.  
  5097. function editPreviewTable(article, h, reallyContribs, timeOffset) {
  5098.     var html=['<table>'];
  5099.     var day=null;
  5100.     var curart=article;
  5101.     for (var i=0; i<h.length; ++i) {
  5102.         if (reallyContribs) { 
  5103.             var page=h[i]['title']; curart = new Title(page);
  5104.         }
  5105.         var minor=typeof h[i]['minor']=='undefined' ? '' : '<b>m </b>';
  5106.         var editDate=adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset);
  5107.         var thisDay = dayFormat(editDate);
  5108.         var thisTime = timeFormat(editDate);
  5109.         if (thisDay==day) { thisDay=''; }
  5110.         else { day=thisDay; }
  5111.         if (thisDay) {
  5112.             html.push( '<tr><td colspan=3><span class="popup_history_date">' +
  5113.                   thisDay+'</span></td></tr>' );
  5114.         }
  5115.         html.push('<tr class="popup_history_row_' + ( (i%2) ? 'odd' : 'even') + '">');
  5116.         html.push('<td>(<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
  5117.             '&diff=prev&oldid=' + h[i]['revid'] + '">' + popupString('last') + '</a>)</td>');
  5118.         html.push('<td>' +
  5119.             '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() +
  5120.             '&oldid=' + h[i]['revid'] + '">' + thisTime + '</a></td>');
  5121.         var col3url='', col3txt='';
  5122.         if (!reallyContribs) {
  5123.             var user=h[i]['user'];
  5124.             col3url=pg.wiki.titlebase + pg.ns.user + ':' + new Title(user).urlString();
  5125.             col3txt=escapeQuotesHTML(user);
  5126.         } else {
  5127.             col3url=pg.wiki.titlebase + curart.urlString();
  5128.             col3txt=escapeQuotesHTML(page);
  5129.         }
  5130.         html.push('<td>' + (reallyContribs ? minor : '') +
  5131.             '<a href="' + col3url + '">' + col3txt + '</a></td>');
  5132.         var comment='';
  5133.         var c=h[i].comment || h[i]['*'];
  5134.         if (c) {
  5135.             comment=new Previewmaker(c, new Title(curart).toUrl()).editSummaryPreview();
  5136.         }
  5137.         html.push('<td>' + (!reallyContribs ? minor : '') + comment + '</td>');
  5138.         html.push('</tr>');
  5139.         html=[html.join('')];
  5140.     }
  5141.     html.push('</table>');
  5142.     return html.join('');
  5143. }
  5144.  
  5145. function getDateFromTimestamp(t) {
  5146.     var s=t.split(/[^0-9]/);
  5147.     switch(s.length) {
  5148.     case 0: return null;
  5149.     case 1: return new Date(s[0]);
  5150.     case 2: return new Date(s[0], s[1]-1);
  5151.     case 3: return new Date(s[0], s[1]-1, s[2]);
  5152.     case 4: return new Date(s[0], s[1]-1, s[2], s[3]);
  5153.     case 5: return new Date(s[0], s[1]-1, s[2], s[3], s[4]);
  5154.     case 6: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]);
  5155.     default: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5], s[6]);
  5156.     }
  5157. }
  5158.  
  5159. function adjustDate(d, offset) {
  5160.     // offset is in minutes
  5161.     var o=offset * 60 * 1000;
  5162.     return new Date( +d + o);
  5163. }
  5164.  
  5165. function dayFormat(editDate, utc) {
  5166.     if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); }
  5167.     return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-');
  5168. }
  5169.  
  5170. function timeFormat(editDate, utc) {
  5171.     if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); }
  5172.     return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':');
  5173. }
  5174.  
  5175. function showAPIPreview(queryType, html, id, navpop, download) {
  5176.     // DJ: done
  5177.     var target='popupPreview';
  5178.     switch (queryType) {
  5179.     case 'imagelinks':
  5180.     case 'category':
  5181.     case 'userinfo':
  5182.         target='popupPostPreview'; break;
  5183.     }
  5184.     setPopupTipsAndHTML(html, target, id);
  5185.     completedNavpopTask(navpop);
  5186. }
  5187.  
  5188. function APIbacklinksPreviewHTML(article, download, navpop) {
  5189.     try {
  5190.         var jsObj=getJsObj(download.data);
  5191.            var list=jsObj.query.backlinks;
  5192.     } catch (someError) { return 'backlinksPreviewHTML went wonky'; }
  5193.     var html=[];
  5194.     if (!list) { return popupString('No backlinks found'); }
  5195.     for ( i in list ) {
  5196.         var t=new Title(list[i]['title']);
  5197.         html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>');
  5198.     }
  5199.     html=html.join(', ');
  5200.     if (jsObj['query-continue'] && jsObj['query-continue'].backlinks && jsObj['query-continue'].backlinks.blcontinue) {
  5201.         html += popupString(' and more');
  5202.     }
  5203.     return html;
  5204. }
  5205.  
  5206. function APIsharedImagePagePreviewHTML(obj) {
  5207.     log( "APIsharedImagePagePreviewHTML" );
  5208.     var popupid = obj['requestid'];
  5209.     if( obj['query'] && obj['query']['pages'] )
  5210.     {
  5211.         var page=anyChild(obj['query']['pages']);
  5212.         var content=(page && page.revisions ) ? page.revisions[0]['*'] : null;
  5213.         if( content ) 
  5214.         {
  5215.             /* Not entirely safe, but the best we can do */
  5216.             var p=new Previewmaker(content, pg.current.link.navpopup.article, pg.current.link.navpopup);
  5217.             p.makePreview();
  5218.             setPopupHTML( p.html, "popupSecondPreview", popupid );
  5219.         }
  5220.     }
  5221. }
  5222.  
  5223. function APIimagepagePreviewHTML(article, download, navpop) {
  5224.     try {
  5225.         var jsObj=getJsObj(download.data);
  5226.         var page=anyChild(jsObj.query.pages);
  5227.         var content=(page && page.revisions ) ? page.revisions[0]['*'] : null;
  5228.     } catch (someError) {
  5229.         return 'API imagepage preview failed :(';
  5230.     }
  5231.     var ret='';
  5232.     if (content) {
  5233.         var p=prepPreviewmaker(content, article, navpop);
  5234.         p.makePreview();
  5235.         if (p.html) { ret += '<hr>' + p.html; }
  5236.     }
  5237.     if (content!==null && getValueOf('popupSummaryData')) {
  5238.         var info=getPageInfo(content, download);
  5239.         log(info);
  5240.         setPopupTrailer(info, navpop.idNumber);
  5241.     }
  5242.     if (page && page.imagerepository == "shared" ) {
  5243.         var art=new Title(article).urlString();
  5244.         var shared_url =  pg.wiki.commonsbase + '/api.php?format=json&callback=APIsharedImagePagePreviewHTML' +
  5245.                             '&requestid=' + navpop.idNumber +
  5246.                             '&action=query&prop=revisions&rvprop=content&titles=' + art;
  5247.         ret = ret +'<hr>' + popupString( 'Image from Commons') +
  5248.                 ': <a href="' + pg.wiki.commonsbase + '/index.php?title=' + art + '">' +
  5249.                 popupString( 'Description page') + '</a>';
  5250.         importScriptURI( shared_url );
  5251.     }
  5252.     showAPIPreview('imagelinks', APIimagelinksPreviewHTML(article,download), navpop.idNumber, download);
  5253.     return ret;
  5254. }
  5255.  
  5256. function APIimagelinksPreviewHTML(article, download) {
  5257.     try {
  5258.         var jsobj=getJsObj(download.data);
  5259.         var list=jsobj.query.imageusage;
  5260.         if (!list) { return popupString('No image links found'); }
  5261.     } catch(someError) { return 'Image links preview generation failed :('; }
  5262.     var ret=[];
  5263.     for (var i=0; i < list.length; i++) {
  5264.         ret.push(list[i]['title']);
  5265.     }
  5266.     if (ret.length === 0) { return popupString('No image links found'); }
  5267.     return '<h2>' + popupString('File links') + '</h2>' + linkList(ret);
  5268. }
  5269.  
  5270. function APIcategoryPreviewHTML(article, download) {
  5271.     try{
  5272.         var jsobj=getJsObj(download.data);
  5273.         var list=jsobj.query.categorymembers;
  5274.     } catch(someError) { return 'Category preview failed :('; }
  5275.     var ret=[];
  5276.     for (var p=0; p < list.length; p++) { 
  5277.        ret.push(list[p]['title']); 
  5278.     }
  5279.     if (ret.length === 0) { return popupString('Empty category'); }
  5280.     ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret);
  5281.     if (jsobj['query-continue'] && jsobj['query-continue'].categorymembers && jsobj['query-continue'].categorymembers.cmcontinue) {
  5282.         ret += popupString(' and more');
  5283.     }
  5284.     return ret;
  5285. }
  5286.  
  5287. function APIuserInfoPreviewHTML(article, download) {
  5288.     try{
  5289.         var jsobj=getJsObj(download.data);
  5290.         var user=anyChild(jsobj.query.users);
  5291.     } catch(someError) { return 'Userinfo preview failed :('; }
  5292.     if (!user || user.invalid == '') {
  5293.         return '<hr>' + popupString( 'Invalid or IP user');
  5294.     } else if (user.missing == '') {
  5295.         return '<hr>' + popupString( 'Not a registered username');
  5296.     }
  5297.     var ret=[];
  5298.     if( user.blockedby )
  5299.         ret.push('<b>' + popupString('BLOCKED') + '</b>');
  5300.     for( var i=0; (user.groups && i < user.groups.length); i++)
  5301.     {
  5302.         ret.push( user.groups[i] );
  5303.     }
  5304.     if( user.editcount || user.registration )
  5305.         ret.push( (user.editcount?user.editcount:'') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'') );
  5306.     ret = '<hr>' + ret.join( ', ' );
  5307.     return ret;
  5308. }
  5309.  
  5310. function APIcontribsPreviewHTML(article, download, navpop) {
  5311.     return APIhistoryPreviewHTML(article, download, navpop, true);
  5312. }
  5313.  
  5314. function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) {
  5315.     try {
  5316.         var jsobj=getJsObj(download.data);
  5317.         var tz=jsobj.query.userinfo.options.timecorrection;
  5318.         if( reallyContribs )
  5319.             var edits=jsobj.query.usercontribs;
  5320.         else 
  5321.             var edits=anyChild(jsobj.query.pages)['revisions'];
  5322.     } catch (someError) {
  5323.         return 'History preview failed :-(';
  5324.     }
  5325.     var timeOffset = getTimeOffset(tz);
  5326.     Cookie.create('popTz', timeOffset, 1);
  5327.  
  5328.     var ret=editPreviewTable(article, edits, reallyContribs, timeOffset);
  5329.     return ret;
  5330. }
  5331.  
  5332.  
  5333. //</NOLITE>
  5334. // ENDFILE: querypreview.js
  5335. // STARTFILE: debug.js
  5336. ////////////////////////////////////////////////////////////////////
  5337. // Debugging functions
  5338. ////////////////////////////////////////////////////////////////////
  5339.  
  5340. function log(){}; // dummy to stop errors
  5341. function setupDebugging() {
  5342. //<NOLITE>
  5343.     if (window.popupDebug) { // popupDebug is set from .version
  5344.         window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; };
  5345.             window.console.log(x);
  5346.         }
  5347.         window.errlog=function(x) {
  5348.             window.console.error(x);
  5349.         }
  5350.         log('Initializing logger');
  5351.     } else {
  5352. //</NOLITE>
  5353.         window.log = function(x) {};
  5354.         window.errlog = function(x) {};
  5355. //<NOLITE>
  5356.     }
  5357. //</NOLITE>
  5358. }
  5359. // ENDFILE: debug.js
  5360. // STARTFILE: images.js
  5361. //<NOLITE>
  5362. // FIXME rewrite ALL of this
  5363. // How the URLs for images in the popup come about
  5364.  
  5365. //   loadPreview
  5366. //          |
  5367. //       getWiki
  5368. //          |<----------------see other schematic for details
  5369. //    insertPreview      (insertPreview = onComplete)
  5370. //          |
  5371. //          |            insertPreview gets a wikiText fragment from
  5372. //          |                       the wikiText downloaded by getWiki
  5373. //          |
  5374. //  [wikiMarkupToAddressFragment]
  5375. //       |
  5376. //       |                     mouseOverWikiLink  (gets an "address fragment",
  5377. //       |                            |            no processing needed)
  5378. //       \->-*loadThisImage---<----loadImages
  5379. //                  |
  5380. //           [image(Thumb)URL]-->--hopefully valid image urls
  5381.  
  5382. // FIXME get rid of pg.idNumber
  5383.  
  5384. function sequentialLoadThisImage (image) {
  5385.     if (!getValueOf('popupImages')) { return false; }
  5386.     if (!isValidImageName(image)) { return false; }
  5387.  
  5388.     var imageUrls=getImageUrls(image);
  5389.     if (!imageUrls) { return null; }
  5390.  
  5391.     var img=new Image();
  5392.     img.isNew=true;
  5393.     img.pg.idNumber=pg.idNumber;
  5394.     img.counter=1;
  5395.  
  5396.     img.onload = function () {
  5397.         // clear status thingy
  5398.         setImageStatus('');
  5399.  
  5400.         var i=findThis(imageUrls, this.src);
  5401.         var goodSrc=this.src;
  5402.  
  5403.         var setPopupImage=function () {
  5404.             var popupImage=content.document.getElementById("popupImage"+this.pg.idNumber);
  5405.             if (popupImage && typeof popupImage.src != 'undefined') {
  5406.                 clearInterval(pg.timer.image);
  5407.                 popupImage.src=goodSrc;
  5408.                 popupImage.width=getValueOf('popupImageSize');
  5409.                 popupImage.style.display='inline';
  5410.                 setPopupImageLink(image, pg.wiki.imageSources[i].wiki);
  5411.                 return true;
  5412.             } else { return false; }
  5413.         };
  5414.         pg.timer.image=setInterval(setPopupImage, 250);
  5415.         pg.cache.images.push(goodSrc);
  5416.     };
  5417.  
  5418.     img.onerror = function () {
  5419.         pg.cache.badImageUrls.push(this.src);
  5420.     };
  5421.  
  5422.     img.setNext = function () {
  5423.         var currentSrc=null;
  5424.         var newSrc;
  5425.         if (!this.isNew) { currentSrc=this.src; }
  5426.         this.isNew=false;
  5427.  
  5428.         newSrc= (currentSrc) ? nextOne(imageUrls, currentSrc) : imageUrls[0];
  5429.  
  5430.         while (findThis(pg.cache.badImageUrls, newSrc))  {
  5431.             newSrc=nextOne(imageUrls, newSrc);
  5432.             if (!newSrc) {
  5433.                 setImageStatus (' :-(');
  5434.                 return;
  5435.             }
  5436.         }
  5437.         setImageStatus(' '+findThis(imageUrls, newSrc));
  5438.         this.src=newSrc;
  5439.     };
  5440.  
  5441.     // start the ball rolling
  5442.     img.setNext();
  5443.  
  5444. }
  5445.  
  5446. function loadThisImageAtThisUrl(image, url) {
  5447.     log('loading "best" image:\n'+url);
  5448.     pg.misc.gImage=new Title(image.toString());
  5449.     pg.misc.imageArray = [];
  5450.     pg.misc.imageArray[0] = new Image();
  5451.     pg.misc.imageArray[0].src=url;
  5452.     if (pg.timer.image || pg.timer.image===0) {
  5453.         clearInterval(pg.timer.image);
  5454.         pg.counter.checkImages=0;
  5455.     }
  5456.     pg.timer.image=setInterval(checkImages, 250);
  5457.     return;
  5458. }
  5459.  
  5460. // methinks this is unbelievably silly
  5461. // it dovetails with the parallel image loader function
  5462. function checkImages() {
  5463.     //log('checkImages: pg.counter.loop='+pg.counter.loop+'; pg.counter.checkImages='+pg.counter.checkImages);
  5464.     if (pg.timer.checkImages || pg.timer.checkImages===0) {
  5465.         clearInterval(pg.timer.checkImages);
  5466.         pg.timer.checkImages=null;
  5467.         if (pg.counter.loop > 10) {pg.counter.loop=0; log('too many iterations of checkImages'); return;}
  5468.         pg.counter.loop++;
  5469.     } else pg.counter.checkImages++;
  5470.  
  5471.     var status =  ( pg.counter.checkImages % 2 ) ? ':' : '.' ;
  5472.     setImageStatus(status);
  5473.  
  5474.     if (pg.counter.checkImages > 100) {
  5475.         pg.counter.checkImages = 0;
  5476.         log ('pg.counter.checkImages too big in checkImages; returning');
  5477.         clearInterval(pg.timer.image);
  5478.     }
  5479.  
  5480.     var popupImage=null;
  5481.     popupImage=content.document.getElementById("popupImg"+pg.idNumber);
  5482.     if (popupImage == null) {
  5483.         // this doesn't seem to happen any more in practise for some reason
  5484.         // still, I'll leave it in
  5485.         log('checkImages: document.getElementById("popupImg'+pg.idNumber+'") is null! retrying in 333ms...');
  5486.         pg.timer.checkImages=setInterval("checkImages()",333);
  5487.         return;
  5488.     }
  5489.  
  5490.     log('checkImages: found element popupImg'+pg.idNumber+', and src='+popupImage.src);
  5491.  
  5492.     // get the first image to successfully load
  5493.     // and put it in the popupImage
  5494.     for(var i = 0; i < pg.misc.imageArray.length; ++i) {
  5495.         if(isImageOk(pg.misc.imageArray[i])) {
  5496.             // stop all the gubbins, assign the image and return
  5497.  
  5498.             log('checkImages: got at pos '+i+', src='+pg.misc.imageArray[i].src);
  5499.             clearInterval(pg.timer.image);
  5500.  
  5501.             if(pg.misc.gImage && pg.misc.gImage.namespace() == pg.ns.image) {
  5502.                 popupImage.src=pg.misc.imageArray[i].src;
  5503.                 popupImage.width=getValueOf('popupImageSize');
  5504.                 popupImage.style.display='inline';
  5505.                 // should we check to see if it's already there? maybe...
  5506.                 pg.cache.images.push(pg.misc.imageArray[i].src);
  5507.  
  5508.                 setPopupImageLink(pg.misc.gImage, pg.wiki.imageSources[i].wiki);
  5509.                 stopImagesDownloading();
  5510.             }
  5511.  
  5512.             setImageStatus('');
  5513.  
  5514.             // reset evil nonconstant globals
  5515.             delete pg.misc.imageArray; pg.misc.imageArray=[];
  5516.             pg.timer.image=null;
  5517.  
  5518.             pg.counter.checkImages=0;
  5519.             pg.counter.loop=0;
  5520.  
  5521.             return popupImage.src;
  5522.         }
  5523.     }
  5524.     log('checkImages: no good image found. retrying in a tic...');
  5525.     pg.timer.checkImages=setInterval("checkImages()",333);
  5526. }
  5527.  
  5528. function stopImagesDownloading() {
  5529.     pg.misc.gImage=null;
  5530.     if (pg.misc.imageArray == null) { return null; }
  5531.     for (var i=0; i<pg.misc.imageArray.length; ++i) {
  5532.         //pg.misc.imageArray[i].src=''; // this is a REALLY BAD IDEA
  5533.         delete pg.misc.imageArray[i];
  5534.         //pg.misc.imageArray[i] = new Image();
  5535.     }
  5536.     pg.misc.imageArray = [];
  5537. }
  5538.  
  5539. function toggleSize() {
  5540.     var imgContainer=this;
  5541.     if (!imgContainer) { alert('imgContainer is null :/'); return;}
  5542.     img=imgContainer.firstChild;
  5543.     if (!img) { alert('img is null :/'); return;}
  5544.     if (!img.style.width || img.style.width=='') { img.style.width='100%'; }
  5545.     else { img.style.width=''; }
  5546. }
  5547.  
  5548. function setPopupImageLink (img, wiki) {
  5549.     if( wiki === null || img === null ) { return null; }
  5550.  
  5551.     var a=content.document.getElementById("popupImageLink"+pg.idNumber);
  5552.     if (a === null) { return null; }
  5553.  
  5554.     switch (getValueOf('popupThumbAction')) {
  5555.     case 'imagepage':
  5556.         if (pg.current.article.namespace()!=pg.ns.image) {
  5557.             a.href=pg.wiki.titlebase + img.urlString();
  5558.             // FIXME: unreliable pg.idNumber
  5559.             popTipsSoonFn('popupImage' + pg.idNumber)();
  5560.             break;
  5561.         } // else fall through
  5562.     case 'sizetoggle':
  5563.         a.onclick=toggleSize;
  5564.         a.title=popupString('Toggle image size');
  5565.         return;
  5566.     case 'linkfull':
  5567.         var linkURL = imageURL(img, wiki);
  5568.         if (linkURL) {
  5569.             a.href = linkURL;
  5570.             a.title=popupString('Open full-size image');
  5571.         }
  5572.         return;
  5573.     }
  5574. }
  5575.  
  5576. function isImageOk(img) {
  5577.     // IE test
  5578.     if (!img.complete) { return false; }
  5579.  
  5580.     // gecko test
  5581.     if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) { return false; }
  5582.  
  5583.     // test for konqueror and opera
  5584.  
  5585.     // note that img.width must not be defined in the html with a width="..."
  5586.     // for this to work.
  5587.  
  5588.     // konq seems to give "broken images" width 16, presumably an icon width
  5589.     // this test would probably work in gecko too, *except for very small images*
  5590.     if (typeof img.width == 'undefined' || img.width <=  16) { return false; }
  5591.  
  5592.     // No other way of checking: assume it's ok.
  5593.     return true;
  5594. }
  5595.  
  5596. // those odd a/a5/ bits of image urls
  5597. function imagePathComponent(article) { // article is string, no namespace
  5598.     // FIXME needs testing with odd characters
  5599.     var forhash=article.split(' ').join('_');
  5600.     var hash=hex_md5(forhash);
  5601.     return hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
  5602. }
  5603.  
  5604. function getImageUrlStart(wiki) { // this returns a trailing slash
  5605.     switch (wiki) {
  5606.     case 'en.wikipedia.org':  return 'http://upload.wikimedia.org/wikipedia/en/';
  5607.     case pg.wiki.commons:     return 'http://upload.wikimedia.org/wikipedia/commons/';
  5608.     case 'en.wiktionary.org': return 'http://en.wiktionary.org/upload/en/';
  5609.     case 'secure.wikimedia.org':
  5610.         return joinPath(['http://upload.wikimedia.org', pg.wiki.prePath]) + '/'; break;
  5611.     default: // unsupported - take a guess
  5612.         if (pg.wiki.wikimedia) {
  5613.             return 'http://upload.wikimedia.org/wikipedia/' + pg.wiki.lang +'/';
  5614.         }
  5615.         /* this should work for wikicities */
  5616.         return 'http://' + wiki + '/images/';
  5617.     }
  5618. }
  5619.  
  5620. function imageURL(img, wiki) {
  5621.     if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
  5622.     var imgurl=null;
  5623.     var pathcpt = imagePathComponent(img.stripNamespace());
  5624.     imgurl=getImageUrlStart(wiki) + pathcpt + img.stripNamespace().split(' ').join('_');
  5625.     return imgurl;
  5626. }
  5627.  
  5628. function imageThumbURL(img, wiki, width) {
  5629.     //
  5630.     // eg http://upload.wikimedia.org/wikipedia/en/thumb/6/61/
  5631.     //           Rubiks_cube_solved.jpg/120px-Rubiks_cube_solved.jpg
  5632.     //           ^^^^^^^^^^^^^^^^^^^^^^^
  5633.     //          wikicities omits this bit
  5634.     //  AND wikicities needs a new pathcpt for each filename including thumbs
  5635.  
  5636.     if (getValueOf('popupImagesFromThisWikiOnly') && wiki != pg.wiki.hostname) return null;
  5637.     if (getValueOf('popupNeverGetThumbs')) return null;
  5638.  
  5639.     var imgurl=null;
  5640.     var stripped=img.stripNamespace();
  5641.     var pathcpt;
  5642.     if (pg.wiki.wikimedia) pathcpt = imagePathComponent(stripped);
  5643.     else pathcpt = imagePathComponent(width+'px-'+stripped);
  5644.     imgurl=getImageUrlStart(wiki) +  "thumb/" + pathcpt;
  5645.     if (pg.wiki.wikimedia) imgurl += stripped + '/';
  5646.     imgurl += width +"px-" + stripped;
  5647.     return imgurl;
  5648. }
  5649.  
  5650. function loadImages(image) {
  5651.     if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); }
  5652.     if (getValueOf('popupLoadImagesSequentially')) { return sequentialLoadThisImage(image); }
  5653.     return parallelLoadThisImage(image);
  5654. }
  5655.  
  5656. function getImageUrls(image) {
  5657.     if (typeof image.stripNamespace != 'function') { alert('getImageUrls bad'); }
  5658.     var imageUrls=[];
  5659.     for (var i=0; i<pg.wiki.imageSources.length; ++i) {
  5660.         var url;
  5661.         if (pg.wiki.imageSources[i].thumb) {
  5662.             url=imageThumbURL(image, pg.wiki.imageSources[i].wiki, pg.wiki.imageSources[i].width);
  5663.         } else { url=imageURL(image, pg.wiki.imageSources[i].wiki); }
  5664.         for (var j=0; j<pg.cache.images.length; ++j) {
  5665.             if (url == pg.cache.images[j]) {
  5666.                 loadThisImageAtThisUrl(image, url);
  5667.                 return null;
  5668.             }
  5669.         }
  5670.         if (url!=null) imageUrls.push(url);
  5671.     }
  5672.     return imageUrls;
  5673. }
  5674.  
  5675.  
  5676. // this is probably very wasteful indeed of bandwidth
  5677. // hey ho
  5678.  
  5679. function parallelLoadThisImage (image) {
  5680.     if (typeof image.stripNamespace != 'function') { alert('parallelLoadThisImage bad'); }
  5681.     if (!getValueOf('popupImages')) return;
  5682.     if (!isValidImageName(image)) return false;
  5683.  
  5684.     var imageUrls=getImageUrls(image);
  5685.     if (!imageUrls) return null;
  5686.  
  5687.     for (var i=0; i<imageUrls.length; ++i) {
  5688.         var url = imageUrls[i];
  5689.         pg.misc.imageArray[i]=new Image();
  5690.         pg.misc.imageArray[i].src=url;
  5691.     }
  5692.     if (pg.timer.image != null) {
  5693.         clearInterval(pg.timer.image);
  5694.         pg.counter.checkImages=0;
  5695.     }
  5696.     pg.misc.gImage=new Title(image.toString());
  5697.     pg.timer.image=setInterval("checkImages()", 250);
  5698.     return true;
  5699. }
  5700.  
  5701. function getValidImageFromWikiText(wikiText) {
  5702.     var imagePage=null;
  5703.     // nb in pg.re.image we're interested in the second bracketed expression
  5704.     // this may change if the regex changes :-(
  5705.     //var match=pg.re.image.exec(wikiText);
  5706.     var matched=null;
  5707.     var match;
  5708.     // strip html comments, used by evil bots :-(
  5709.     var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1,
  5710.                     RegExp('^<!--[^[]*popup', 'i'));
  5711.  
  5712.     while ( match = pg.re.image.exec(t) ) {
  5713.         // now find a sane image name - exclude templates by seeking {
  5714.         var m = match[2] || match[6];
  5715.         var pxWidth=match[4];
  5716.         if ( isValidImageName(m) &&
  5717.              (!pxWidth || parseInt(pxWidth,10) >= getValueOf('popupMinImageWidth')) ) {
  5718.             matched=m;
  5719.             break;
  5720.         }
  5721.     }
  5722.     pg.re.image.lastIndex=0;
  5723.     if (!matched) { return null; }
  5724.     return pg.ns.image+':'+upcaseFirst(matched);
  5725. }
  5726.  
  5727. function removeMatchesUnless(str, re1, parencount, re2) {
  5728.     var split=str.parenSplit(re1);
  5729.     var c=parencount + 1;
  5730.     for (var i=0; i<split.length; ++i) {
  5731.     if ( i%c === 0 || re2.test(split[i]) ) { continue; }
  5732.     split[i]='';
  5733.     }
  5734.     return split.join('');
  5735. }
  5736.  
  5737. //</NOLITE>
  5738. // ENDFILE: images.js
  5739. // STARTFILE: namespaces.js
  5740. // Set up namespaces and other non-strings.js localization
  5741. // (currently that means redirs too)
  5742.  
  5743. // Put the right namespace list into pg.ns.list, based on pg.wiki.lang
  5744. // Default to english if nothing seems to fit
  5745. function setNamespaceList() {
  5746.     var m="Media";
  5747.     var list = [m, "Special", "Talk", "User", "User talk", "Wikipedia", "Wikipedia talk", "File", "File talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", "Portal", "Portal talk"];
  5748.     var nsIndex = { '': 0, 'Special': 1,
  5749.             'Talk': 2, 'User': 3, 'User talk': 4, 'Wikipedia': 5,
  5750.             'Wikipedia talk': 6, 'Image': 7, 'File': 7, 'Image talk': 8, 'File talk' : 8, 'MediaWiki': 9,
  5751.             'MediaWiki talk': 10, 'Template': 11, 'Template talk': 12,
  5752.             'Help': 13, 'Help talk': 14, 'Category': 15, 'Category talk':16,
  5753.             'Portal': 17, 'Portal talk': 18};
  5754.     var nsLists = {
  5755. //<NOLITE>
  5756.         "af": [m, "Spesiaal", "Bespreking", "Gebruiker", "Gebruikerbespreking", "Wikipedia", "Wikipediabespreking", "Beeld", "Beeldbespreking", "MediaWiki", "MediaWikibespreking", "Sjabloon", "Sjabloonbespreking", "Hulp", "Hulpbespreking", "Kategorie", "Kategoriebespreking"],
  5757.         "als": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion"],
  5758.         "ar": ["┘à┘ä┘ü", "╪«╪º╪╡", "┘å┘é╪º╪┤", "┘à╪│╪¬╪«╪»┘à", "┘å┘é╪º╪┤ ╪º┘ä┘à╪│╪¬╪«╪»┘à", "┘ê┘è┘â┘è╪¿┘è╪»┘è╪º", "┘å┘é╪º╪┤ ┘ê┘è┘â┘è╪¿┘è╪»┘è╪º", "╪╡┘ê╪▒╪⌐", "┘å┘é╪º╪┤ ╪º┘ä╪╡┘ê╪▒╪⌐", "┘à┘è╪»┘è╪º┘ê┘è┘â┘è", "┘å┘é╪º╪┤ ┘à┘è╪»┘è╪º┘ê┘è┘â┘è", "Template", "┘å┘é╪º╪┤ Template", "┘à╪│╪º╪╣╪»╪⌐", "┘å┘é╪º╪┤ ╪º┘ä┘à╪│╪º╪╣╪»╪⌐", "╪¬╪╡┘å┘è┘ü", "┘å┘é╪º╪┤ ╪º┘ä╪¬╪╡┘å┘è┘ü"],
  5759.         "ast": [m, "Especial", "Discusi├│n", "Usuariu", "Usuariu discusi├│n", "Uiquipedia", "Uiquipedia discusi├│n", "Imaxen", "Imaxen discusi├│n", "MediaWiki", "MediaWiki discusi├│n", "Plantilla", "Plantilla discusi├│n", "Ayuda", "Ayuda discusi├│n", "Categor├¡a", "Categor├¡a discusi├│n"],
  5760.         "be": ["╨£╤ì╨┤╤ï╤Å", "╨í╨┐╤ì╤å╤ï╤Å╨╗╤î╨╜╤ï╤Å", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡", "╨ú╨┤╨╖╨╡╨╗╤î╨╜╤û╨║", "╨ô╤â╤é╨░╤Ç╨║╤û ╤₧╨┤╨╖╨╡╨╗╤î╨╜╤û╨║╨░", "╨Æ╤û╨║╤û╨┐╤ì╨┤╤ï╤Å", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ ╨Æ╤û╨║╤û╨┐╤ì╨┤╤ï╤Å", "╨Æ╤ï╤Å╨▓╨░", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ ╨▓╤ï╤Å╨▓╤ï", "MediaWiki", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ MediaWiki", "╨¿╨░╨▒╨╗╤æ╨╜", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ ╤ê╨░╨▒╨╗╤æ╨╜╤â", "╨ö╨░╨┐╨░╨╝╨╛╨│╨░", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ ╨┤╨░╨┐╨░╨╝╨╛╨│╤û", "╨Ü╨░╤é╤ì╨│╨╛╤Ç╤ï╤Å", "╨É╨▒╨╝╨╡╤Ç╨║╨░╨▓╨░╨╜╤î╨╜╨╡ ╨║╨░╤é╤ì╨│╨╛╤Ç╤ï╤û"],
  5761.         "bg": ["╨£╨╡╨┤╨╕╤Å", "╨í╨┐╨╡╤å╨╕╨░╨╗╨╜╨╕", "╨æ╨╡╤ü╨╡╨┤╨░", "╨ƒ╨╛╤é╤Ç╨╡╨▒╨╕╤é╨╡╨╗", "╨ƒ╨╛╤é╤Ç╨╡╨▒╨╕╤é╨╡╨╗ ╨▒╨╡╤ü╨╡╨┤╨░", "╨ú╨╕╨║╨╕╨┐╨╡╨┤╨╕╤Å", "╨ú╨╕╨║╨╕╨┐╨╡╨┤╨╕╤Å ╨▒╨╡╤ü╨╡╨┤╨░", "╨Ü╨░╤Ç╤é╨╕╨╜╨║╨░", "╨Ü╨░╤Ç╤é╨╕╨╜╨║╨░ ╨▒╨╡╤ü╨╡╨┤╨░", "╨£╨╡╨┤╨╕╤Å╨ú╨╕╨║╨╕", "╨£╨╡╨┤╨╕╤Å╨ú╨╕╨║╨╕ ╨▒╨╡╤ü╨╡╨┤╨░", "╨¿╨░╨▒╨╗╨╛╨╜", "╨¿╨░╨▒╨╗╨╛╨╜ ╨▒╨╡╤ü╨╡╨┤╨░", "╨ƒ╨╛╨╝╨╛╤ë", "╨ƒ╨╛╨╝╨╛╤ë ╨▒╨╡╤ü╨╡╨┤╨░", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤Å", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤Å ╨▒╨╡╤ü╨╡╨┤╨░"],
  5762.         "bm": [m, "Special", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikipedia", "Discussion Wikipedia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Mod├¿le", "Discussion Mod├¿le", "Aide", "Discussion Aide", "Cat├⌐gorie", "Discussion Cat├⌐gorie"],
  5763.         "bn": ["বαª┐αª╢αºçαª╖", "αªåαª▓αª╛᪬", "বαºìযবαª╣αª╛αª░αªòαª╛αª░αºÇ", "বαºìযবαª╣αª╛αª░αªòαª╛αª░αºÇ αªåαª▓αª╛᪬", "αªëαªçαªòαª┐᪬αºçαªíαª┐᪻αª╝αª╛", "αªëαªçαªòαª┐᪬αºçαªíαª┐᪻αª╝αª╛ αªåαª▓αª╛᪬", "αªÜαª┐αªñαºìαª░", "αªÜαª┐αªñαºìαª░ αªåαª▓αª╛᪬", "MediaWik i αªåαª▓αª╛᪬", m, "MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5764.         "br": [m, "Dibar", "Kaozeal", "Implijer", "Kaozeadenn Implijer", "Wikipedia", "Kaozeadenn Wikipedia", "Skeudenn", "Kaozeadenn Skeudenn", "MediaWiki", "Kaozeadenn MediaWiki", "Patrom", "Kaozeadenn Patrom", "Skoazell", "Kaozeadenn Skoazell", "Rummad", "Kaozeadenn Rummad"],
  5765.         "ca": [m, "Especial", "Discussi├│", "Usuari", "Usuari Discussi├│", "Viquip├¿dia", "Viquip├¿dia Discussi├│", "Imatge", "Imatge Discussi├│", "MediaWiki", "MediaWiki Discussi├│", "Template", "Template Discussi├│", "Ajuda", "Ajuda Discussi├│", "Categoria", "Categoria Discussi├│"],
  5766.         "cs": ["M├⌐dia", "Speci├íln├¡", "Diskuse", "Wikipedista", "Wikipedista diskuse", "Wikipedie", "Wikipedie diskuse", "Soubor", "Soubor diskuse", "MediaWiki", "MediaWiki diskuse", "┼áablona", "┼áablona diskuse", "N├ípov─¢da", "N├ípov─¢da diskuse", "Kategorie", "Kategorie diskuse"],
  5767.         "csb": [m, "Specjaln├┤", "Disk├╣s├½j├┤", "Br├½k├▓wnik", "Disk├╣s├½j├┤ br├½k├▓wnika", "Wiki", "Disk├╣s├½j├┤ Wiki", "├Æbr├┤zk", "Disk├╣s├½j├┤ ├▓br├┤zk├│w", "MediaWiki", "Disk├╣s├½j├┤ MediaWiki", "Szabl├│na", "Disk├╣s├½j├┤ Szabl├│n├½", "P├▓m├▓c", "Disk├╣s├½j├┤ P├▓m├▓c├½", "Kateg├▓r├½j├┤", "Disk├╣s├½j├┤ Kateg├▓r├½ji"],
  5768.         "cv": ["╨£╨╡╨┤╨╕╨░", "╨»╤é╨░╤Ç╨╗─â", "╨í╙│╤é╤ü╨╡ ╤Å╨▓╨░╤ü╤ü╨╕", "╨Ñ╤â╤é╤ê─â╨╜╨░╨║╨░╨╜", "╨Ñ╤â╤é╤ê─â╨╜╨░╨║╨░╨╜─â╨╜ ╨║╨░╨╜╨░╤ê╨╗╤â ╤ü╤é╤Ç╨░╨╜╨╕╤å╨╕", "Wikipedia", "0", "╙▓╨║╨╡╤Ç╤ç─ò╨║", "╙▓╨║╨╡╤Ç╤ç─ò╨║╨╡ ╤ü╙│╤é╤ü╨╡ ╤Å╨▓╨╝╨░╨╗╨╗╨╕", "MediaWiki", "MediaWiki ╤ü╙│╤é╤ü╨╡ ╤Å╨▓╨╝╨░╨╗╨╗╨╕", "╨¿╨░╨▒╨╗╨╛╨╜", "╨¿╨░╨▒╨╗╨╛╨╜╨░ ╤ü╙│╤é╤ü╨╡ ╤Å╨▓╨╝╨░╨╗╨╗╨╕", "╨ƒ╤â╨╗─â╤ê╤â", "╨ƒ╤â╨╗─â╤ê─â╨▓╨░ ╤ü╙│╤é╤ü╨╡ ╤Å╨▓╨╝╨░╨╗╨╗╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╨╜╨╡ ╤ü╙│╤é╤ü╨╡ ╤Å╨▓╨╝╨░╨╗╨╗╨╕"],
  5769.         "cy": [m, "Arbennig", "Sgwrs", "Defnyddiwr", "Sgwrs Defnyddiwr", "Wicipedia", "Sgwrs Wicipedia", "Delwedd", "Sgwrs Delwedd", "MediaWiki", "Sgwrs MediaWiki", "Nodyn", "Sgwrs Nodyn", "Help", "Help talk", "Category", "Category talk"],
  5770.         "da": [m, "Speciel", "Diskussion", "Bruger", "Brugerdiskussion", "Wikipedia", "Wikipedia-diskussion", "Billede", "Billeddiskussion", "MediaWiki", "MediaWiki-diskussion", "Skabelon", "Skabelondiskussion", "Hj├ªlp", "Hj├ªlpdiskussion", "Kategori", "Kategoridiskussion", "Portal", "Portaldiskussion"],
  5771.         "de": [m, "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikipedia", "Wikipedia Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion", "Portal", "Portal Diskussion"],
  5772.         "el": ["╬£╬¡╧â╬┐╬╜", "╬ò╬╣╬┤╬╣╬║╧î", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖", "╬º╧ü╬«╧â╧ä╬╖╧é", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖ ╧ç╧ü╬«╧â╧ä╬╖", "╬Æ╬╣╬║╬╣╧Ç╬▒╬»╬┤╬╡╬╣╬▒", "╬Æ╬╣╬║╬╣╧Ç╬▒╬»╬┤╬╡╬╣╬▒ ╧â╧à╬╢╬«╧ä╬╖╧â╬╖", "╬ò╬╣╬║╧î╬╜╬▒", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖ ╬╡╬╣╬║╧î╬╜╬▒╧é", "MediaWiki", "MediaWiki talk", "╬á╧ü╧î╧ä╧à╧Ç╬┐", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖ ╧Ç╧ü╬┐╧ä╧ì╧Ç╬┐╧à", "╬Æ╬┐╬«╬╕╬╡╬╣╬▒", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖ ╬▓╬┐╬«╬╕╬╡╬╣╬▒╧é", "╬Ü╬▒╧ä╬╖╬│╬┐╧ü╬»╬▒", "╬ú╧à╬╢╬«╧ä╬╖╧â╬╖ ╬║╬▒╧ä╬╖╬│╬┐╧ü╬»╬▒╧é"],
  5773.         "eo": [m, "Speciala", "Diskuto", "Vikipediisto", "Vikipediista diskuto", "Vikipedio", "Vikipedio diskuto", "Dosiero", "Dosiera diskuto", "MediaWiki", "MediaWiki diskuto", "┼£ablono", "┼£ablona diskuto", "Helpo", "Helpa diskuto", "Kategorio", "Kategoria diskuto"],
  5774.         "es": [m, "Especial", "Discusi├│n", "Usuario", "Usuario Discusi├│n", "Wikipedia", "Wikipedia Discusi├│n", "Imagen", "Imagen Discusi├│n", "MediaWiki", "MediaWiki Discusi├│n", "Plantilla", "Plantilla Discusi├│n", "Ayuda", "Ayuda Discusi├│n", "Categor├¡a", "Categor├¡a Discusi├│n"],
  5775.         "et": ["Meedia", "Eri", "Arutelu", "Kasutaja", "Kasutaja arutelu", "Vikipeedia", "Vikipeedia arutelu", "Pilt", "Pildi arutelu", "MediaWiki", "MediaWiki arutelu", "Mall", "Malli arutelu", "Juhend", "Juhendi arutelu", "Kategooria", "Kategooria arutelu"],
  5776.         "eu": [m, "Aparteko", "Eztabaida", "Lankide", "Lankide eztabaida", "Wikipedia", "Wikipedia eztabaida", "Irudi", "Irudi eztabaida", "MediaWiki", "MediaWiki eztabaida", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5777.         "fa": ["┘à╪»█î╪º", "┘ê█î┌ÿ┘ç", "╪¿╪¡╪½", "┌⌐╪º╪▒╪¿╪▒", "╪¿╪¡╪½ ┌⌐╪º╪▒╪¿╪▒", "┘ê█î┌⌐█îΓÇî┘╛╪»█î╪º", "╪¿╪¡╪½ ┘ê█î┌⌐█îΓÇî┘╛╪»█î╪º", "╪¬╪╡┘ê█î╪▒", "╪¿╪¡╪½ ╪¬╪╡┘ê█î╪▒", "┘à╪»█î╪º┘ê█î┌⌐█î", "╪¿╪¡╪½ ┘à╪»█î╪º┘ê█î┌⌐█î", "╪º┘ä┌»┘ê", "╪¿╪¡╪½ ╪º┘ä┌»┘ê", "╪▒╪º┘ç┘å┘à╪º", "╪¿╪¡╪½ ╪▒╪º┘ç┘å┘à╪º", "╪▒╪»┘ç", "╪¿╪¡╪½ ╪▒╪»┘ç"],
  5778.         "fi": [m, "Toiminnot", "Keskustelu", "K├ñytt├ñj├ñ", "Keskustelu k├ñytt├ñj├ñst├ñ", "Wikipedia", "Keskustelu Wikipediasta", "Kuva", "Keskustelu kuvasta", "MediaWiki", "MediaWiki talk", "Malline", "Keskustelu mallineesta", "Ohje", "Keskustelu ohjeesta", "Luokka", "Keskustelu luokasta"],
  5779.         "fo": ["Mi├░il", "Serstakur", "Kjak", "Br├║kari", "Br├║kari kjak", "Wikipedia", "Wikipedia kjak", "Mynd", "Mynd kjak", "MidiaWiki", "MidiaWiki kjak", "Fyrimynd", "Fyrimynd kjak", "Hj├ílp", "Hj├ílp kjak", "B├│lkur", "B├│lkur kjak"],
  5780.         "fr": [m, "Sp├⌐cial", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikip├⌐dia", "Discussion Wikip├⌐dia", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Mod├¿le", "Discussion Mod├¿le", "Aide", "Discussion Aide", "Cat├⌐gorie", "Discussion Cat├⌐gorie", "Portail", "Discussion Portail"],
  5781.         "fur": [m, "Speci├ól", "Discussion", "Utent", "Discussion utent", "Vichipedie", "Discussion Vichipedie", "Figure", "Discussion figure", "MediaWiki", "Discussion MediaWiki", "Model", "Discussion model", "Jutori", "Discussion jutori", "Categorie", "Discussion categorie"],
  5782.         "fy": [m, "Wiki", "Oerlis", "Meidogger", "Meidogger oerlis", "Wikipedy", "Wikipedy oerlis", "Ofbyld", "Ofbyld oerlis", "MediaWiki", "MediaWiki oerlis", "Berjocht", "Berjocht oerlis", "Hulp", "Hulp oerlis", "Kategory", "Kategory oerlis"],
  5783.         "ga": ["Me├ín", "Speisialta", "Pl├⌐", "├Üs├íideoir", "Pl├⌐ ├║s├íideora", "Vicip├⌐id", "Pl├⌐ Vicip├⌐ide", "├ìomh├í", "Pl├⌐ ├¡omh├í", "MediaWiki", "Pl├⌐ MediaWiki", "Teimpl├⌐ad", "Pl├⌐ teimpl├⌐id", "Cabhair", "Pl├⌐ cabhrach", "Catag├│ir", "Pl├⌐ catag├│ire"],
  5784.         "gu": [m, "Special", "Talk", "User", "User talk", "α¬╡α¬┐α¬òα¬┐ᬬα½Çα¬íα¬┐ᬻα¬╛", "α¬╡α¬┐α¬òα¬┐ᬬα½Çα¬íα¬┐ᬻα¬╛ talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5785.         "he": [m, "╫₧╫Ö╫ò╫ù╫ô", "╫⌐╫Ö╫ù╫ö", "╫₧╫⌐╫¬╫₧╫⌐", "╫⌐╫Ö╫ù╫¬ ╫₧╫⌐╫¬╫₧╫⌐", "╫ò╫Ö╫º╫Ö╫ñ╫ô╫Ö╫ö", "╫⌐╫Ö╫ù╫¬ ╫ò╫Ö╫º╫Ö╫ñ╫ô╫Ö╫ö", "╫¬╫₧╫ò╫á╫ö", "╫⌐╫Ö╫ù╫¬ ╫¬╫₧╫ò╫á╫ö", "MediaWiki", "╫⌐╫Ö╫ù╫¬ MediaWiki", "╫¬╫æ╫á╫Ö╫¬", "╫⌐╫Ö╫ù╫¬ ╫¬╫æ╫á╫Ö╫¬", "╫ó╫û╫¿╫ö", "╫⌐╫Ö╫ù╫¬ ╫ó╫û╫¿╫ö", "╫º╫ÿ╫Æ╫ò╫¿╫Ö╫ö", "╫⌐╫Ö╫ù╫¬ ╫º╫ÿ╫Æ╫ò╫¿╫Ö╫ö"],
  5786.         "hi": [m, "αñ╡αñ┐αñ╢αÑçαñ╖", "αñ╡αñ╛αñ░αÑìαññαñ╛", "αñ╕αñªαñ╕αÑìαñ»", "αñ╕αñªαñ╕αÑìαñ» αñ╡αñ╛αñ░αÑìαññαñ╛", "αñ╡αñ┐αñòαñ┐αñ¬αÑÇαñíαñ┐αñ»αñ╛", "αñ╡αñ┐αñòαñ┐αñ¬αÑÇαñíαñ┐αñ»αñ╛ αñ╡αñ╛αñ░αÑìαññαñ╛", "αñÜαñ┐αññαÑìαñ░", "αñÜαñ┐αññαÑìαñ░ αñ╡αñ╛αñ░αÑìαññαñ╛", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "αñ╢αÑìαñ░αÑçαñúαÑÇ", "αñ╢αÑìαñ░αÑçαñúαÑÇ αñ╡αñ╛αñ░αÑìαññαñ╛", "Help", "Help talk"],
  5787.         "hr": ["Mediji", "Posebno", "Razgovor", "Suradnik", "Razgovor sa suradnikom", "Wikipedia", "Razgovor Wikipedia", "Slika", "Razgovor o slici", "MediaWiki", "MediaWiki razgovor", "Predlo┼╛ak", "Razgovor o predlo┼íku", "Pomo─ç", "Razgovor o pomo─çi", "Kategorija", "Razgovor o kategoriji"],
  5788.         "hu": [ "M├⌐dia", "Speci├ílis", "Vita", "Szerkeszt┼æ", "Szerkeszt┼ævita", "Wikip├⌐dia", "Wikip├⌐dia-vita", "K├⌐p", "K├⌐pvita", "MediaWiki", "MediaWiki-vita", "Sablon", "Sablonvita", "Seg├¡ts├⌐g", "Seg├¡ts├⌐gvita", "Kateg├│ria", "Kateg├│riavita", "Port├íl", "Port├ílvita"],
  5789.         "ia": [m, "Special", "Discussion", "Usator", "Discussion Usator", "Wikipedia", "Discussion Wikipedia", "Imagine", "Discussion Imagine", "MediaWiki", "Discussion MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5790.         //"Gambar" not working, changing it for "Berkas"
  5791.         "id": [m, "Istimewa", "Bicara", "Pengguna", "Bicara Pengguna", "Wikipedia", "Pembicaraan Wikipedia", "Berkas", "Pembicaraan Gambar", "MediaWiki", "Pembicaraan MediaWiki", "Templat", "Pembicaraan Templat", "Bantuan", "Pembicaraan Bantuan", "Kategori", "Pembicaraan Kategori"],
  5792.         "is": ["Mi├░ill", "Kerfiss├¡├░a", "Spjall", "Notandi", "Notandaspjall", "Wikipedia", "Wikipediaspjall", "Mynd", "Myndaspjall", "Melding", "Meldingarspjall", "Sni├░", "Sni├░aspjall", "Hj├ílp", "Hj├ílparspjall", "Flokkur", "Flokkaspjall"],
  5793.         "it": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "File", "Discussioni file", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria", "Portale", "Discussioni portale", "Progetto", "Discussioni progetto"],
  5794.         "ja": [m, "τë╣σêÑ", "πâÄπâ╝πâê", "σê⌐τö¿ΦÇà", "σê⌐τö¿ΦÇàΓÇÉΣ╝ÜΦ⌐▒", "Wikipedia", "WikipediaΓÇÉπâÄπâ╝πâê", "τö╗σâÅ", "τö╗σâÅΓÇÉπâÄπâ╝πâê", "MediaWiki", "MediaWikiΓÇÉπâÄπâ╝πâê", "Template", "TemplateΓÇÉπâÄπâ╝πâê", "Help", "HelpΓÇÉπâÄπâ╝πâê", "Category", "CategoryΓÇÉπâÄπâ╝πâê"],
  5795.         "ka": ["ßâ¢ßâößâôßâÿßâÉ", "ßâíßâ₧ßâößâ¬ßâÿßâÉßâÜßâúßâáßâÿ", "ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâ¢ßâ¥ßâ¢ßâ«ßâ¢ßâÉßâáßâößâæßâößâÜßâÿ", "ßâ¢ßâ¥ßâ¢ßâ«ßâ¢ßâÉßâáßâößâæßâößâÜßâÿ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâòßâÿßâÖßâÿßâ₧ßâößâôßâÿßâÉ", "ßâòßâÿßâÖßâÿßâ₧ßâößâôßâÿßâÉ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâíßâúßâáßâÉßâùßâÿ", "ßâíßâúßâáßâÉßâùßâÿ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâ¢ßâößâôßâÿßâÉßâòßâÿßâÖßâÿ", "ßâ¢ßâößâôßâÿßâÉßâòßâÿßâÖßâÿ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâùßâÉßâáßâÆßâÿ", "ßâùßâÉßâáßâÆßâÿ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâôßâÉßâ«ßâ¢ßâÉßâáßâößâæßâÉ", "ßâôßâÉßâ«ßâ¢ßâÉßâáßâößâæßâÉ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ", "ßâÖßâÉßâóßâößâÆßâ¥ßâáßâÿßâÉ", "ßâÖßâÉßâóßâößâÆßâ¥ßâáßâÿßâÉ ßâÆßâÉßâ£ßâ«ßâÿßâÜßâòßâÉ"],
  5796.         "ko": [m, "φè╣∞êÿΩ╕░δèÑ", "φåáδíá", "∞é¼∞Ü⌐∞₧É", "∞é¼∞Ü⌐∞₧Éφåáδíá", "∞£äφéñδ░▒Ω│╝", "∞£äφéñδ░▒Ω│╝φåáδíá", "Ω╖╕δª╝", "Ω╖╕δª╝φåáδíá", "δ╢äδÑÿ", "δ╢äδÑÿφåáδíá", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk"],
  5797.         "ku": ["Medya", "Taybet", "N├«qa┼ƒ", "Bikarh├¬ner", "Bikarh├¬ner n├«qa┼ƒ", "W├«k├«pediya", "W├«k├«pediya n├«qa┼ƒ", "W├¬ne", "W├¬ne n├«qa┼ƒ", "MediaWiki", "MediaWiki n├«qa┼ƒ", "┼₧ablon", "┼₧ablon n├«qa┼ƒ", "Al├«kar├«", "Al├«kar├« n├«qa┼ƒ", "Kategor├«", "Kategor├« n├«qa┼ƒ"],
  5798.         "la": ["Specialis", "Disputatio", "Usor", "Disputatio Usoris", "Vicipaedia", "Disputatio Vicipaediae", "Imago", "Disputatio Imaginis", "MediaWiki", "Disputatio MediaWiki", "Formula", "Disputatio Formulae", "Auxilium", "Disputatio Auxilii", "Categoria", "Disputatio Categoriae", m],
  5799.         "li": [m, "Speciaal", "Euverlik", "Gebroeker", "Euverlik gebroeker", "Wikipedia", "Euverlik Wikipedia", "Aafbeilding", "Euverlik afbeelding", "MediaWiki", "Euverlik MediaWiki", "Sjabloon", "Euverlik sjabloon", "Help", "Euverlik help", "Kategorie", "Euverlik kategorie"],
  5800.         "lt": ["Medija", "Specialus", "Aptarimas", "Naudotojas", "Naudotojo aptarimas", "Wikipedia", "Wikipedia aptarimas", "Vaizdas", "Vaizdo aptarimas", "MediaWiki", "MediaWiki aptarimas", "┼áablonas", "┼áablono aptarimas", "Pagalba", "Pagalbos aptarimas", "Kategorija", "Kategorijos aptarimas"],
  5801.         "mk": ["╨£╨╡╨┤╨╕╤ÿ╨░", "╨í╨┐╨╡╤å╨╕╤ÿ╨░╨╗╨╜╨╕", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨Ü╨╛╤Ç╨╕╤ü╨╜╨╕╨║", "╨Ü╨╛╤Ç╨╕╤ü╨╜╨╕╨║ ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "Wikipedia", "Wikipedia ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨í╨╗╨╕╨║╨░", "╨í╨╗╨╕╨║╨░ ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨£╨╡╨┤╨╕╤ÿ╨░╨Æ╨╕╨║╨╕", "╨£╨╡╨┤╨╕╤ÿ╨░╨Æ╨╕╨║╨╕ ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨¿╨░╨▒╨╗╨╛╨╜", "╨¿╨░╨▒╨╗╨╛╨╜ ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨ƒ╨╛╨╝╨╛╤ê", "╨ƒ╨╛╨╝╨╛╤ê ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤ÿ╨░", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤ÿ╨░ ╤Ç╨░╨╖╨│╨╛╨▓╨╛╤Ç"],
  5802.         "ms": [m, "Istimewa", "Perbualan", "Pengguna", "Perbualan Pengguna", "Wikipedia", "Perbualan Wikipedia", "Imej", "Imej Perbualan", "MediaWiki", "MediaWiki Perbualan", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5803.         "mt": [m, "Special", "Talk", "User", "User talk", "Wikipedija", "Wikipedija talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5804.         "nap": [m, "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikipedia", "Discussioni Wikipedia", "Immagine", "Discussioni immagine", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria"],
  5805.         "nds": [m, "Spezial", "Diskuschoon", "Bruker", "Bruker Diskuschoon", "Wikipedia", "Wikipedia Diskuschoon", "Bild", "Bild Diskuschoon", "MediaWiki", "MediaWiki Diskuschoon", "V├╢rlaag", "V├╢rlaag Diskuschoon", "H├╝lp", "H├╝lp Diskuschoon", "Kategorie", "Kategorie Diskuschoon"],
  5806.         "nl": [m, "Speciaal", "Overleg", "Gebruiker", "Overleg gebruiker", "Wikipedia", "Overleg Wikipedia", "Afbeelding", "Overleg afbeelding", "MediaWiki", "Overleg MediaWiki", "Sjabloon", "Overleg sjabloon", "Help", "Overleg help", "Categorie", "Overleg categorie"],
  5807.         "nn": ["Filpeikar", "Spesial", "Diskusjon", "Brukar", "Brukardiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Fil", "Fildiskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
  5808.         "no": ["Medium", "Spesial", "Diskusjon", "Bruker", "Brukerdiskusjon", "Wikipedia", "Wikipedia-diskusjon", "Bilde", "Bildediskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"],
  5809.         "nv": [m, "Special", "Naaltsoos baa yin├¡sht'─»╠ü", "Choinish'─»─»h├¡", "Choinish'─»─»h├¡ baa yin├¡sht'─»╠ü", "Wikiib├¡├¡diiya", "Wikiib├¡├¡diiya baa yin├¡sht'─»╠ü", "E'elyaa├¡g├¡├¡", "E'elyaa├¡g├¡├¡ baa yin├¡sht'─»╠ü", "MediaWiki", "MediaWiki baa yin├¡sht'─»╠ü", "Template", "Template talk", "An├í'├ílwo'", "An├í'├ílwo' baa yin├¡sht'─»╠ü", "T'├í├í┼é├íh├ígi ├ít'├⌐ego", "T'├í├í┼é├íh├ígi ├ít'├⌐ego baa yin├¡sht'─»╠ü"],
  5810.         "oc": ["Especial", "Discutir", "Utilisator", "Discutida Utilisator", "Oiquipedi├á", "Discutida Oiquipedi├á", "Image", "Discutida Image", "MediaWiki", "MediaWiki talk", "Template", "Template talk", m, "Help", "Help talk", "Category", "Category talk"],
  5811.         "os": [m, "╨í├ª╤Ç╨╝╨░╨│╨╛╨╜╨┤", "╨ö╨╕╤ü╨║╤â╤ü╤ü╨╕", "╨É╤Ç╤à╨░╨╣├ª╨│", "╨É╤Ç╤à╨░╨╣├ª╨┤╨╢╤ï ╨┤╨╕╤ü╨║╤â╤ü╤ü╨╕", "Wikipedia", "0", "╨¥╤ï╨▓", "╨¥╤ï╨▓╤ï ╤é╤ï╤à╤à├ª╨╣ ╨┤╨╕╤ü╨║╤â╤ü╤ü╨╕", "MediaWiki", "╨ö╨╕╤ü╨║╤â╤ü╤ü╨╕ MediaWiki", "╨¿╨░╨▒╨╗╨╛╨╜", "╨¿╨░╨▒╨╗╨╛╨╜╤ï ╤é╤ï╤à╤à├ª╨╣ ╨┤╨╕╤ü╨║╤â╤ü╤ü╨╕", "├å╤à╤à╤â╤ï╤ü", "├å╤à╤à╤â╤ï╤ü╤ï ╤é╤ï╤à╤à├ª╨╣ ╨┤╨╕╤ü╨║╤â╤ü╤ü╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╨╣╤ï ╤é╤ï╤à╤à├ª╨╣ ╨┤╨╕╤ü╨║╤â╤ü╤ü╨╕"],
  5812.         "pa": ["α¿«α⌐Çα¿íα⌐Çα¿å", "α¿ûα¿╛α¿╕", "α¿Üα¿░α¿Üα¿╛", "α¿«α⌐êα¿éα¿¼α¿░", "α¿«α⌐êα¿éα¿¼α¿░ α¿Üα¿░α¿Üα¿╛", "Wikipedia", "Wikipedia α¿Üα¿░α¿Üα¿╛", "α¿ñα¿╕α¿╡α⌐Çα¿░", "α¿ñα¿╕α¿╡α⌐Çα¿░ α¿Üα¿░α¿Üα¿╛", "α¿«α⌐Çα¿íα⌐Çα¿åα¿╡α¿┐α¿òα¿┐", "α¿«α⌐Çα¿íα⌐Çα¿åα¿╡α¿┐α¿òα¿┐ α¿Üα¿░α¿Üα¿╛", "α¿¿α¿«α⌐éα¿¿α¿╛", "α¿¿α¿«α⌐éα¿¿α¿╛ α¿Üα¿░α¿Üα¿╛", "ਮਦਦ", "ਮਦਦ α¿Üα¿░α¿Üα¿╛", "α¿╕α¿╝α⌐ìα¿░α⌐çα¿úα⌐Ç", "α¿╕α¿╝α⌐ìα¿░α⌐çα¿úα⌐Ç α¿Üα¿░α¿Üα¿╛"],
  5813.         "pl": [m, "Specjalna", "Dyskusja", "Wikipedysta", "Dyskusja wikipedysty", "Wikipedia", "Dyskusja Wikipedii", "Plik", "Dyskusja pliku", "MediaWiki", "Dyskusja MediaWiki", "Szablon", "Dyskusja szablonu", "Pomoc", "Dyskusja pomocy", "Kategoria", "Dyskusja kategorii", "Portal", "Dyskusja portalu","Wikiprojekt","Dyskusja Wikiprojektu"],
  5814.         "pt": [m, "Especial", "Discuss├úo", "Usu├írio", "Usu├írio Discuss├úo", "Wikipedia", "Wikipedia Discuss├úo", "Imagem", "Imagem Discuss├úo", "MediaWiki", "MediaWiki Discuss├úo", "Predefini├º├úo", "Predefini├º├úo Discuss├úo", "Ajuda", "Ajuda Discuss├úo", "Categoria", "Categoria Discuss├úo"],
  5815.         "ro": [m, "Special", "Discu┼úie", "Utilizator", "Discu┼úie Utilizator", "Wikipedia", "Discu┼úie Wikipedia", "Imagine", "Discu┼úie Imagine", "MediaWiki", "Discu┼úie MediaWiki", "Format", "Discu┼úie Format", "Ajutor", "Discu┼úie Ajutor", "Categorie", "Discu┼úie Categorie"],
  5816.         "ru": ["╨£╨╡╨┤╨╕╨░", "╨í╨╗╤â╨╢╨╡╨▒╨╜╨░╤Å", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡", "╨ú╤ç╨░╤ü╤é╨╜╨╕╨║", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╤â╤ç╨░╤ü╤é╨╜╨╕╨║╨░", "╨Æ╨╕╨║╨╕╨┐╨╡╨┤╨╕╤Å", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╨Æ╨╕╨║╨╕╨┐╨╡╨┤╨╕╨╕", "╨ÿ╨╖╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╕╨╡", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╨╕╨╖╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╕╤Å", "MediaWiki", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ MediaWiki", "╨¿╨░╨▒╨╗╨╛╨╜", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╤ê╨░╨▒╨╗╨╛╨╜╨░", "╨í╨┐╤Ç╨░╨▓╨║╨░", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╤ü╨┐╤Ç╨░╨▓╨║╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤Å", "╨₧╨▒╤ü╤â╨╢╨┤╨╡╨╜╨╕╨╡ ╨║╨░╤é╨╡╨│╨╛╤Ç╨╕╨╕"],
  5817.         "sc": ["Speciale", "Conti├¿ndha", "Utente", "Utente discussioni", "Wikipedia", "Wikipedia discussioni", "Imm├ágini", "Imm├ágini conti├¿ndha", m, "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5818.         "sk": ["M├⌐di├í", "┼ápeci├ílne", "Diskusia", "Redaktor", "Diskusia s redaktorom", "Wikip├⌐dia", "Diskusia k Wikip├⌐dii", "Obr├ízok", "Diskusia k obr├ízku", "MediaWiki", "Diskusia k MediaWiki", "┼áabl├│na", "Diskusia k ┼íabl├│ne", "Pomoc", "Diskusia k pomoci", "Kateg├│ria", "Diskusia ku kateg├│rii"],
  5819.         "sl": [m, "Posebno", "Pogovor", "Uporabnik", "Uporabni┼íki pogovor", "Wikipedija", "Pogovor k Wikipediji", "Slika", "Pogovor k sliki", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5820.         "sq": [m, "Speciale", "Diskutim", "P├½rdoruesi", "P├½rdoruesi diskutim", "Wikipedia", "Wikipedia diskutim", "Figura", "Figura diskutim", "MediaWiki", "MediaWiki diskutim", "Stampa", "Stampa diskutim", "Ndihm├½", "Ndihm├½ diskutim", "Category", "Category talk"],
  5821.         "sr": [m, "╨ƒ╨╛╤ü╨╡╨▒╨╜╨╛", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç", "╨Ü╨╛╤Ç╨╕╤ü╨╜╨╕╨║", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╤ü╨░ ╨║╨╛╤Ç╨╕╤ü╨╜╨╕╨║╨╛╨╝", "╨Æ╨╕╨║╨╕╨┐╨╡╨┤╨╕╤ÿ╨░", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╨Æ╨╕╨║╨╕╨┐╨╡╨┤╨╕╤ÿ╨╕", "╨í╨╗╨╕╨║╨░", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╤ü╨╗╨╕╤å╨╕", "╨£╨╡╨┤╨╕╤ÿ╨░╨Æ╨╕╨║╨╕", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╨£╨╡╨┤╨╕╤ÿ╨░╨Æ╨╕╨║╨╕╤ÿ╤â", "╨¿╨░╨▒╨╗╨╛╨╜", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╤ê╨░╨▒╨╗╨╛╨╜╤â", "╨ƒ╨╛╨╝╨╛╤¢", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╨┐╨╛╨╝╨╛╤¢╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╨╕╤ÿ╨░", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╨║╨░╤é╨╡╨│╨╛╤Ç╨╕╤ÿ╨╕", "╨ƒ╨╛╤Ç╤é╨░╨╗", "╨á╨░╨╖╨│╨╛╨▓╨╛╤Ç ╨╛ ╨┐╨╛╤Ç╤é╨░╨╗╤â"],
  5822.         "sv": [m, "Special", "Diskussion", "Anv├ñndare", "Anv├ñndardiskussion", "Wikipedia", "Wikipediadiskussion", "Bild", "Bilddiskussion", "MediaWiki", "MediaWiki diskussion", "Mall", "Malldiskussion", "Hj├ñlp", "Hj├ñlp diskussion", "Kategori", "Kategoridiskussion"],
  5823.         "ta": ["α«è᫃α«òα««α»ì", "α«Üα«┐α«▒᫬α»ì᫬α»ü", "᫬α»çα«Üα»ìα«Üα»ü", "᫬᫻α«⌐α«░α»ì", "᫬᫻α«⌐α«░α»ì α«¬α»çα«Üα»ìα«Üα»ü", "Wikipedia", "Wikipedia α«¬α»çα«Üα»ìα«Üα»ü", "᫬᫃α«┐α««α««α»ì", "᫬᫃α«┐᫫᫬α»ì α«¬α»çα«Üα»ìα«Üα»ü", "α««α»Ç᫃α«┐α«»α«╛α«╡α«┐α«òα»ìα«òα«┐", "α««α»Ç᫃α«┐α«»α«╛α«╡α«┐α«òα»ìα«òα«┐ α«¬α»çα«Üα»ìα«Üα»ü", "α«╡α«╛α«░α»ì᫬α»ì᫬α»üα«░α»ü", "α«╡α«╛α«░α»ì᫬α»ì᫬α»üα«░α»ü α«¬α»çα«Üα»ìα«Üα»ü", "α«ëα«ñα«╡α«┐", "α«ëα«ñα«╡α«┐ α«¬α»çα«Üα»ìα«Üα»ü", "᫬α«òα»ü᫬α»ì᫬α»ü", "᫬α«òα»ü᫬α»ì᫬α»ü α«¬α»çα«Üα»ìα«Üα»ü"],
  5824.         "th": [m, "α╕₧α╕┤α╣Çα╕¿α╕⌐", "α╕₧α╕╣α╕öα╕äα╕╕α╕ó", "α╕£α╕╣α╣ëα╣âα╕èα╣ë", "α╕äα╕╕α╕óα╣Çα╕üα╕╡α╣êα╕óα╕ºα╕üα╕▒α╕Üα╕£α╕╣α╣ëα╣âα╕èα╣ë", "Wikipedia", "Wikipedia talk", "α╕áα╕▓α╕₧", "α╕äα╕╕α╕óα╣Çα╕üα╕╡α╣êα╕óα╕ºα╕üα╕▒α╕Üα╕áα╕▓α╕₧", "MediaWiki", "α╕äα╕╕α╕óα╣Çα╕üα╕╡α╣êα╕óα╕ºα╕üα╕▒α╕Ü MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"],
  5825.         "tlh": ["Doch", "le'", "ja'chuq", "lo'wI'", "lo'wI' ja'chuq", "wIqIpe'DIya", "wIqIpe'DIya ja'chuq", "nagh beQ", "nagh beQ ja'chuq", "MediaWiki", "MediaWiki ja'chuq", "chen'ay'", "chen'ay' ja'chuq", "QaH", "QaH ja'chuq", "Segh", "Segh ja'chuq"],
  5826.         "tr": [m, "├ûzel", "Tart─▒┼ƒma", "Kullan─▒c─▒", "Kullan─▒c─▒ mesaj", "Vikipedi", "Vikipedi tart─▒┼ƒma", "Resim", "Resim tart─▒┼ƒma", "MedyaViki", "MedyaViki tart─▒┼ƒma", "┼₧ablon", "┼₧ablon tart─▒┼ƒma", "Yard─▒m", "Yard─▒m tart─▒┼ƒma", "Kategori", "Kategori tart─▒┼ƒma"],
  5827.         "tt": [m, "Maxsus", "B├ñx├ñs", "├ä─ƒz├ñ", "├ä─ƒz├ñ b├ñx├ñse", "Wikipedia", "Wikipedia b├ñx├ñse", "R├ñsem", "R├ñsem b├ñx├ñse", "MediaWiki", "MediaWiki b├ñx├ñse", "├£rn├ñk", "├£rn├ñk b├ñx├ñse", "Y├ñrd├ñm", "Y├ñrd├ñm b├ñx├ñse", "T├╢rkem", "T├╢rkem b├ñx├ñse"],
  5828.         "uk": ["╨£╨╡╨┤╤û╨░", "╨í╨┐╨╡╤å╤û╨░╨╗╤î╨╜╤û", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å", "╨Ü╨╛╤Ç╨╕╤ü╤é╤â╨▓╨░╤ç", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å ╨║╨╛╤Ç╨╕╤ü╤é╤â╨▓╨░╤ç╨░", "Wikipedia", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å Wikipedia", "╨ù╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╜╤Å", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å ╨╖╨╛╨▒╤Ç╨░╨╢╨╡╨╜╨╜╤Å", "MediaWiki", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å MediaWiki", "╨¿╨░╨▒╨╗╨╛╨╜", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å ╤ê╨░╨▒╨╗╨╛╨╜╤â", "╨ö╨╛╨▓╤û╨┤╨║╨░", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å ╨┤╨╛╨▓╤û╨┤╨║╨╕", "╨Ü╨░╤é╨╡╨│╨╛╤Ç╤û╤Å", "╨₧╨▒╨│╨╛╨▓╨╛╤Ç╨╡╨╜╨╜╤Å ╨║╨░╤é╨╡╨│╨╛╤Ç╤û╤ù"],
  5829.         "vi": ["Ph╞░╞íng tiß╗çn", "─Éß║╖c biß╗çt", "Thß║úo luß║¡n", "Th├ánh vi├¬n", "Thß║úo luß║¡n Th├ánh vi├¬n", "Wikipedia", "Thß║úo luß║¡n Wikipedia", "H├¼nh", "Thß║úo luß║¡n H├¼nh", "MediaWiki", "Thß║úo luß║¡n MediaWiki", "Ti├¬u bß║ún", "Thß║úo luß║¡n Ti├¬u bß║ún", "Trß╗ú gi├║p", "Thß║úo luß║¡n Trß╗ú gi├║p", "Thß╗â loß║íi", "Thß║úo luß║¡n Thß╗â loß║íi"],
  5830.         "wa": [m, "Sipeci├Ñs", "Copene", "Uzeu", "Uzeu copene", "Wikipedia", "Wikipedia copene", "Im├Ñdje", "Im├Ñdje copene", "MediaWiki", "MediaWiki copene", "Modele", "Modele copene", "Aidance", "Aidance copene", "Categoreye", "Categoreye copene"]
  5831. //</NOLITE>
  5832.     };
  5833.     pg.ns.list = nsLists[pg.wiki.lang] || list;
  5834.     pg.ns.index = nsIndex;
  5835. }
  5836.  
  5837. function namespaceListToRegex(list) {return RegExp('^('+list.join('|').split(' ').join('[ _]')+'):');};
  5838. // function setNamespaceList is ugly as sin, moved to later in the code
  5839.  
  5840. function setNamespaces() {
  5841.     setNamespaceList();
  5842.     pg.ns.withTalkList=[null]; // NB root (article) corresponds with this entry, null
  5843.     pg.ns.talkList=[pg.ns.list[2]];
  5844.  
  5845.     // if the number of namespaces changes then this will have to be changed
  5846.     // maybe the easiest way is to specify the arrays by hand as in the comments following the loop
  5847.  
  5848.     for (var i=3; i+1<pg.ns.list.length; i=i+2) {
  5849.         pg.ns.withTalkList.push(pg.ns.list[i]);
  5850.         pg.ns.talkList.push(pg.ns.list[i+1]);
  5851.     }
  5852.  
  5853.     // ALERT! SILLY HARDCODED VALUES FOLLOW!
  5854.     pg.ns.special   = pg.ns.list[pg.ns.index.Special];
  5855.     pg.ns.image     = pg.ns.list[pg.ns.index.File];
  5856.     pg.ns.user      = pg.ns.list[pg.ns.index.User];
  5857.     pg.ns.usertalk  = pg.ns.list[pg.ns.index['User talk']];
  5858.     pg.ns.category  = pg.ns.list[pg.ns.index.Category];
  5859.     pg.ns.template  = pg.ns.list[pg.ns.index.Template];
  5860.     pg.ns.nonArticleList=pg.ns.list.slice(0,2).concat(pg.ns.list.slice(2));
  5861. }
  5862.  
  5863.  
  5864. function setRedirs() {
  5865.     var r='redirect';
  5866.     var R='REDIRECT';
  5867.     var redirLists={
  5868. //<NOLITE>
  5869.         'ar':  [ R, '╪¬╪¡┘ê┘è┘ä' ],
  5870.         'be':  [ r, '╨┐╨╡╤Ç╨░╨╜╨░╨║╤û╤Ç╨░╨▓╨░╨╜╤î╨╜╨╡' ],
  5871.         'bg':  [ r, '╨┐╤Ç╨╡╨╜╨░╤ü╨╛╤ç╨▓╨░╨╜╨╡', '╨▓╨╕╨╢' ],
  5872.         'bs':  [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ],
  5873.         'cs':  [ R, 'P┼ÿESM─ÜRUJ' ],
  5874.         'cy':  [ r, 'ail-cyfeirio' ],
  5875.         'et':  [ r, 'suuna' ],
  5876.         'ga':  [ r, 'athsheoladh' ],
  5877.         'he':  [ R, '╫ö╫ñ╫á╫Ö╫ö' ],
  5878.         'hu':  [ R, '├üTIR├üNY├ìT├üS' ],
  5879.         'is':  [ r, 'tilv├¡sun', 'TILV├ìSUN' ],
  5880.         'it':  [ R, 'RINVIA', 'Rinvia'],
  5881.         'mk':  [ r, '╨┐╤Ç╨╡╨╜╨░╤ü╨╛╤ç╤â╨▓╨░╤Ü╨╡', '╨▓╨╕╨┤╨╕' ],
  5882.         'nds': [ r, 'wiederleiden' ],
  5883.         'nn':  [ r, 'omdiriger' ],
  5884.         'pl':  [ R, 'PATRZ', 'PRZEKIERUJ', 'TAM' ],
  5885.         'pt':  [ R, 'redir' ],
  5886.         'ru':  [ R, '╨ƒ╨ò╨á╨ò╨¥╨É╨ƒ╨á╨É╨Æ╨¢╨ò╨¥╨ÿ╨ò', '╨ƒ╨ò╨á╨ò╨¥╨É╨ƒ╨á' ],
  5887.         'sk':  [ r, 'presmeruj' ],
  5888.         'sr':  [ r, '╨ƒ╤Ç╨╡╤â╤ü╨╝╨╡╤Ç╨╕', '╨┐╤Ç╨╡╤â╤ü╨╝╨╡╤Ç╨╕', '╨ƒ╨á╨ò╨ú╨í╨£╨ò╨á╨ÿ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ],
  5889.         'tt':  [ 'y├╝n├ñlt├╝' ],
  5890.         'vi':  [ r, '─æß╗òi' ] // no comma
  5891. //</NOLITE>
  5892.     };
  5893.     var redirList=redirLists[ pg.wiki.lang ] || [r, R];
  5894.     // Mediawiki is very tolerant about what comes after the #redirect at the start
  5895.     pg.re.redirect=RegExp('^\\s*[#](' + redirList.join('|') + ').*?\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i');
  5896. }
  5897.  
  5898. function setInterwiki() {
  5899.     if (pg.wiki.wikimedia) {
  5900.         pg.wiki.interwiki='aa|ab|af|ak|als|am|an|ang|ar|arc|arz|as|ast|av|ay|az|ba|be|ber|bg|bh|bi|bm|bn|bdf|bo|br|bs|ca|ce|ceb|ch|cho|chr|chy|co|commons|cr|cs|csb|cu|cv|cy|da|de|dsb|dv|dz|el|en|eo|es|et|eu|fa|ff|fi|fiu-vro|fj|fo|fr|fur|fy|ga|gd|gil|gl|gn|got|gu|gv|ha|haw|he|hi|ho|hr|hsb|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|ilo|io|is|it|iu|ja|jbo|jv|ka|kg|ki|kj|kk|kl|km|kn|ko|kr|ks|ksh|ku|kv|kw|ky|la|lad|lan|lb|lg|li|ln|lmo|lo|lt|lu|lv|map-bms|mg|mh|mi|mk|ml|mn|mo|mr|ms|mt|stq|mus|my|na|nah|nap|nb|nd|nds|nds-nl|ne|new|ng|nl|nn|no|nr|nv|ny|oc|oj|om|or|os|pa|pam|pi|pl|pms|ps|pt|qu|rm|rn|ro|roa-rup|ru|rw|sa|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|smg|sn|so|sq|sr|ss|st|stq|su|sv|sw|szl|ta|te|tg|th|ti|tk|tl|tlh|tn|to|tpi|tr|ts|tt|tum|tw|ty|ug|uk|ur|uz|ve|vi|vk|vo|wa|war|wen|wo|xh|yi|yo|za|zh|zh-min-nan|zh-yue|zu';
  5901.         pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':');
  5902.     } else {
  5903.         pg.wiki.interwiki=null;
  5904.         pg.re.interwiki=RegExp('^$');
  5905.     }
  5906. }
  5907.  
  5908. function nsRe(label) {
  5909.     var l=upcaseFirst(label);
  5910.     return nsRegexString(pg.ns.list[pg.ns.index[l]], l);
  5911. }
  5912.  
  5913. function nsReImage() {
  5914.     var str = pg.ns.list[pg.ns.index["File"]];
  5915.     return '(?:' + str + '|' + encodeURI(str) + '|' + upcaseFirst(str) + '|Image|' + upcaseFirst('Image') + ')';
  5916. }
  5917.  
  5918. function nsRegexString(str, extra) {
  5919.     return '(?:' + str + '|' + encodeURI(str) + (extra ? '|' + extra : '') + ')';
  5920. }
  5921.  
  5922. function nsRegex(str, extra) {
  5923.     return RegExp(nsRegexString(str, extra));
  5924. }
  5925. // ENDFILE: namespaces.js
  5926. // STARTFILE: selpop.js
  5927. //<NOLITE>
  5928. function getEditboxSelection() {
  5929.     // see http://www.webgurusforum.com/8/12/0
  5930.     try {
  5931.         var editbox=document.editform.wpTextbox1;
  5932.     } catch (dang) { return; }
  5933.     // IE, Opera
  5934.     if (document.selection) { return document.selection.createRange().text; }
  5935.     // Mozilla
  5936.     var selStart = editbox.selectionStart;
  5937.     var selEnd = editbox.selectionEnd;
  5938.     return (editbox.value).substring(selStart, selEnd);
  5939. }
  5940.  
  5941. function doSelectionPopup() {
  5942.     // popup if the selection looks like [[foo|anything afterwards at all
  5943.     // or [[foo|bar]]text without ']]'
  5944.     // or [[foo|bar]]
  5945.     var sel=getEditboxSelection();
  5946.     var open=sel.indexOf('[[');
  5947.     var pipe=sel.indexOf('|');
  5948.     var close=sel.indexOf(']]');
  5949.     if (open == -1 || ( pipe == -1 && close == -1) ) { return; }
  5950.     if (pipe != -1 && open > pipe || close != -1 && open > close) { return; }
  5951.     if (getValueOf('popupOnEditSelection')=='boxpreview') {
  5952.         return doSeparateSelectionPopup(sel);
  5953.     }
  5954.     var article=new Title(sel.substring(open+2, (pipe < 0) ? close : pipe)).urlString();
  5955.     if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) { 
  5956.         return; 
  5957.     }
  5958.     var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  5959.     a.href=pg.wiki.titlebase + article;
  5960.     mouseOverWikiLink2(a);
  5961.     if (a.navpopup) {
  5962.         a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after');
  5963.     }
  5964. }
  5965.  
  5966. function doSeparateSelectionPopup(str) {
  5967.     var div=content.document.getElementById('selectionPreview');
  5968.     if (!div) {
  5969.         div = document.createElementNS("http://www.w3.org/1999/xhtml",'div');
  5970.         div.id='selectionPreview';
  5971.         try { var box=document.editform.wpTextbox1; }
  5972.         catch (oopsie) { return; }
  5973.         box.parentNode.insertBefore(div, box);
  5974.     }
  5975.     div.innerHTML=wiki2html(str);
  5976.     div.ranSetupTooltipsAlready = false;
  5977.     popTipsSoonFn('selectionPreview')();
  5978. }
  5979. //</NOLITE>
  5980. // ENDFILE: selpop.js
  5981. // STARTFILE: navpopup.js
  5982. /**
  5983.    @fileoverview  Defines two classes: {@link Navpopup} and {@link Mousetracker}.
  5984.  
  5985.    <code>Navpopup</code> describes popups: when they appear, where, what
  5986.    they look like and so on.
  5987.  
  5988.    <code>Mousetracker</code> "captures" the mouse using
  5989.    <code>document.onmousemove</code>.
  5990. */
  5991.  
  5992.  
  5993. /**
  5994.    Creates a new Mousetracker.
  5995.    @constructor
  5996.    @class The Mousetracker class. This monitors mouse movements and manages associated hooks.
  5997. */
  5998. function Mousetracker() {
  5999.     /**
  6000.        Interval to regularly run the hooks anyway, in milliseconds.
  6001.        @type Integer
  6002.     */
  6003.     this.loopDelay=400;
  6004.  
  6005.     /**
  6006.        Timer for the loop.
  6007.        @type Timer
  6008.     */
  6009.     this.timer=null;
  6010.  
  6011.     /**
  6012.        Flag - are we switched on?
  6013.        @type Boolean
  6014.     */
  6015.     this.active=false;
  6016.     /**
  6017.        Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position?
  6018.     */
  6019.     this.dirty=true;
  6020.     /**
  6021.        Array of hook functions.
  6022.        @private
  6023.        @type Array
  6024.     */
  6025.     this.hooks=[];
  6026. }
  6027.  
  6028. /**
  6029.    Adds a hook, to be called when we get events.
  6030.    @param {Function} f A function which is called as
  6031.    <code>f(x,y)</code>. It should return <code>true</code> when it
  6032.    wants to be removed, and <code>false</code> otherwise.
  6033. */
  6034. Mousetracker.prototype.addHook = function (f) {
  6035.     this.hooks.push(f);
  6036. };
  6037.  
  6038. /**
  6039.    Runs hooks, passing them the x
  6040.    and y coords of the mouse.  Hook functions that return true are
  6041.    passed to {@link Mousetracker#removeHooks} for removal.
  6042.    @private
  6043. */
  6044. Mousetracker.prototype.runHooks = function () {
  6045.     if (!this.hooks || !this.hooks.length) { return; }
  6046.     //log('Mousetracker.runHooks; we got some hooks to run');
  6047.     var remove=false;
  6048.     var removeObj={};
  6049.     // this method gets called a LOT -
  6050.     // pre-cache some variables
  6051.     var x=this.x, y=this.y, len = this.hooks.length;
  6052.  
  6053.     for (var i=0; i<len; ++i) {
  6054.         //~ run the hook function, and remove it if it returns true
  6055.         if (this.hooks[i](x, y)===true) {
  6056.             remove=true;
  6057.             removeObj[i]=true;
  6058.         }
  6059.     }
  6060.     if (remove) { this.removeHooks(removeObj); }
  6061. };
  6062.  
  6063. /**
  6064.    Removes hooks.
  6065.    @private
  6066.    @param {Object} removeObj An object whose keys are the index
  6067.    numbers of functions for removal, with values that evaluate to true
  6068. */
  6069. Mousetracker.prototype.removeHooks = function(removeObj) {
  6070.     var newHooks=[];
  6071.     var len = this.hooks.length;
  6072.     for (var i=0; i<len; ++i) {
  6073.         if (! removeObj[i]) { newHooks.push(this.hooks[i]); }
  6074.     }
  6075.     this.hooks=newHooks;
  6076. };
  6077.  
  6078.  
  6079. /**
  6080.    Event handler for mouse wiggles.
  6081.    We simply grab the event, set x and y and run the hooks.
  6082.    This makes the cpu all hot and bothered :-(
  6083.    @private
  6084.    @param {Event} e Mousemove event
  6085. */
  6086. Mousetracker.prototype.track=function (e) {
  6087.     //~ Apparently this is needed in IE.
  6088.     e = e || window.event;
  6089.     var x, y;
  6090.     if (e) {
  6091.         if (e.pageX) { x=e.pageX; y=e.pageY; }
  6092.         else if (typeof e.clientX!='undefined') {
  6093.             var left, top, docElt = window.document.documentElement;
  6094.  
  6095.             if (docElt) { left=docElt.scrollLeft; }
  6096.             left = left || window.document.body.scrollLeft || window.document.scrollLeft || 0;
  6097.  
  6098.             if (docElt) { top=docElt.scrollTop; }
  6099.             top = top || window.document.body.scrollTop || window.document.scrollTop || 0;
  6100.  
  6101.             x=e.clientX + left;
  6102.             y=e.clientY + top;
  6103.         } else { return; }
  6104.         this.setPosition(x,y);
  6105.     }
  6106. };
  6107.  
  6108. /**
  6109.    Sets the x and y coordinates stored and takes appropriate action,
  6110.    running hooks as appropriate.
  6111.    @param {Integer} x, y Screen coordinates to set
  6112. */
  6113.  
  6114. Mousetracker.prototype.setPosition=function(x,y) {
  6115.     this.x = x;
  6116.     this.y = y;
  6117.     if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; }
  6118.     if (typeof this.lastHook_x != 'number') { this.lastHook_x = -100; this.lastHook_y=-100; }
  6119.     var diff = (this.lastHook_x - x)*(this.lastHook_y - y);
  6120.     diff = (diff >= 0) ? diff : -diff;
  6121.     if ( diff > 1 ) {
  6122.         this.lastHook_x=x;
  6123.         this.lastHook_y=y;
  6124.         if (this.dirty) { this.dirty = false; }
  6125.         else { this.runHooks(); }
  6126.     }
  6127. }
  6128.  
  6129. /**
  6130.    Sets things in motion, unless they are already that is, registering an event handler on <code>document.onmousemove</code>.
  6131.    A half-hearted attempt is made to preserve the old event handler if there is one.
  6132. */
  6133. Mousetracker.prototype.enable = function () {
  6134.     if (this.active) { return; }
  6135.     this.active=true;
  6136.     //~ Save the current handler for mousemove events. This isn't too
  6137.     //~ robust, of course.
  6138.     this.savedHandler=document.onmousemove;
  6139.     //~ Gotta save @tt{this} again for the closure, and use apply for
  6140.     //~ the member function.
  6141.     var savedThis=this;
  6142.     document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);};
  6143.     if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working');
  6144.                                     savedThis.runHooks();}, this.loopDelay); }
  6145. };
  6146.  
  6147. /**
  6148.    Disables the tracker, removing the event handler.
  6149. */
  6150. Mousetracker.prototype.disable = function () {
  6151.     if (!this.active) { return; }
  6152.     if (typeof this.savedHandler=='function') {
  6153.         document.onmousemove=this.savedHandler;
  6154.     } else { delete document.onmousemove; }
  6155.     if (this.timer) { clearInterval(this.timer); }
  6156.     this.active=false;
  6157. };
  6158.  
  6159. /**
  6160.    Creates a new Navpopup.
  6161.    Gets a UID for the popup and
  6162.    @param init Contructor object. If <code>init.draggable</code> is true or absent, the popup becomes draggable.
  6163.    @constructor
  6164.    @class The Navpopup class. This generates popup hints, and does some management of them.
  6165. */
  6166. function Navpopup(init) {
  6167.     //alert('new Navpopup(init)');
  6168.     /** UID for each Navpopup instance.
  6169.         Read-only.
  6170.         @type integer
  6171.     */
  6172.     this.uid=Navpopup.uid++;
  6173.     /**
  6174.        Read-only flag for current visibility of the popup.
  6175.        @type boolean
  6176.        @private
  6177.     */
  6178.     this.visible=false;
  6179.     /** Flag to be set when we want to cancel a previous request to
  6180.         show the popup in a little while.
  6181.         @private
  6182.         @type boolean
  6183.     */
  6184.     this.noshow=false;
  6185.     /** Categorised list of hooks.
  6186.         @see #runHooks
  6187.         @see #addHook
  6188.         @private
  6189.         @type Object
  6190.     */
  6191.     this.hooks={
  6192.         'create': [],
  6193.         'unhide': [],
  6194.         'hide': []
  6195.     };
  6196.     /** list of unique IDs of hook functions, to avoid duplicates
  6197.         @private
  6198.     */
  6199.     this.hookIds={};
  6200.     /** List of downloads associated with the popup.
  6201.         @private
  6202.         @type Array
  6203.     */
  6204.     this.downloads=[];
  6205.     /** Number of uncompleted downloads.
  6206.         @type integer
  6207.     */
  6208.     this.pending=null;
  6209.     /** Tolerance in pixels when detecting whether the mouse has left the popup.
  6210.         @type integer
  6211.     */
  6212.     this.fuzz=5;
  6213.     /** Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position.
  6214.         @type boolean
  6215.     */
  6216.     this.constrained=true;
  6217.     /** The popup width in pixels.
  6218.         @private
  6219.         @type integer
  6220.     */
  6221.     this.width=0;
  6222.     /** The popup width in pixels.
  6223.         @private
  6224.         @type integer
  6225.     */
  6226.     this.height=0;
  6227.     /** The main content DIV element.
  6228.         @type HTMLDivElement
  6229.     */
  6230.     this.mainDiv=null;
  6231.     this.createMainDiv();
  6232.  
  6233. //    if (!init || typeof init.draggable=='undefined' || init.draggable) {
  6234. //        this.makeDraggable(true);
  6235. //    }
  6236. }
  6237.  
  6238. /**
  6239.    A UID for each Navpopup. This constructor property is just a counter.
  6240.    @type integer
  6241.    @private
  6242. */
  6243. Navpopup.uid=0;
  6244.  
  6245. /**
  6246.    Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible.
  6247.    @type boolean
  6248. */
  6249. Navpopup.prototype.isVisible=function() {
  6250.     return this.visible;
  6251. };
  6252.  
  6253. /**
  6254.    Repositions popup using CSS style.
  6255.    @private
  6256.    @param {integer} x x-coordinate (px)
  6257.    @param {integer} y y-coordinate (px)
  6258.    @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition}
  6259. */
  6260. Navpopup.prototype.reposition= function (x,y, noLimitHor) {
  6261.     log ('reposition('+x+','+y+','+noLimitHor+')');
  6262.     if (typeof x != 'undefined' && x!==null) { this.left=x; }
  6263.     if (typeof y != 'undefined' && y!==null) { this.top=y; }
  6264.     if (typeof this.left != 'undefined' && typeof this.top != 'undefined') {
  6265.         this.mainDiv.style.left=this.left + 'px';
  6266.         this.mainDiv.style.top=this.top + 'px';
  6267.     }
  6268.     if (!noLimitHor) { this.limitHorizontalPosition(); }
  6269.     /*if (this.mainDiv.style.left!=""&&typeof x != 'undefined' && x!==null&&typeof y != 'undefined' && y!==null) {
  6270.         if (WikiLook_Overlay._DIVrepositionedTo!=x+y) {
  6271.             if (WikiLook_Overlay._DIVrepositionedTo!="") WikiLook_Overlay._DIVrepositioned=true;
  6272.             WikiLook_Overlay._DIVrepositionedTo=x+y;
  6273.         
  6274.     } else {
  6275.         WikiLook_Overlay._DIVrepositionedTo!="";
  6276.     }*/
  6277.  
  6278.     //console.log('navpop'+this.uid+' - (left,top)=(' + this.left + ',' + this.top + '), css=('
  6279.     //+ this.mainDiv.style.left + ',' + this.mainDiv.style.top + ')');
  6280. };
  6281.  
  6282. /**
  6283.    Prevents popups from being in silly locations. Hopefully.
  6284.    Should not be run if {@link #constrained} is true.
  6285.    @private
  6286. */
  6287. Navpopup.prototype.limitHorizontalPosition=function() {
  6288.     if (!this.constrained || this.tooWide) { return; }
  6289.     this.updateDimensions();
  6290.     var x=this.left;
  6291.     var w=this.width;
  6292.     var cWidth=content.document.body.clientWidth;
  6293.  
  6294.  
  6295. //    log('limitHorizontalPosition: x='+x+
  6296. //            ', this.left=' + this.left +
  6297. //            ', this.width=' + this.width +
  6298. //            ', cWidth=' + cWidth);
  6299.  
  6300.  
  6301.     if ( (x+w) >= cWidth ||
  6302.          ( x > 0 && this.maxWidth && this.width < this.maxWidth && this.height > this.width
  6303.            && x > cWidth - this.maxWidth ) ) {
  6304.         // This is a very nasty hack. There has to be a better way!
  6305.         // We find the "natural" width of the div by positioning it at the far left
  6306.         // then reset it so that it should be flush right (well, nearly)
  6307.         this.mainDiv.style.left='-10000px';
  6308.         this.mainDiv.style.width = this.maxWidth + 'px';
  6309.         var naturalWidth=parseInt(this.mainDiv.offsetWidth, 10);
  6310.         var newLeft=cWidth - naturalWidth - 1;
  6311.         if (newLeft < 0) { newLeft = 0; this.tooWide=true; } // still unstable for really wide popups?
  6312.         log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth);
  6313.         this.reposition(newLeft, null, true);
  6314.         //this._DIVrepositioned=false;
  6315.     }
  6316. };
  6317.  
  6318. /**
  6319.    Counter indicating the z-order of the "highest" popup.
  6320.    We start the z-index at 1000 so that popups are above everything
  6321.    else on the screen.
  6322.    @private
  6323.    @type integer
  6324. */
  6325. Navpopup.highest=1000;
  6326.  
  6327. /**
  6328.    Brings popup to the top of the z-order.
  6329.    We increment the {@link #highest} property of the contructor here.
  6330.    @private
  6331. */
  6332. Navpopup.prototype.raise = function () {
  6333.     this.mainDiv.style.zIndex=WikiLook_Overlay._divZIndex + 1;
  6334.     ++WikiLook_Overlay._divZIndex;
  6335. };
  6336.  
  6337. /**
  6338.    Shows the popup provided {@link #noshow} is not true.
  6339.    Updates the position, brings the popup to the top of the z-order and unhides it.
  6340. */
  6341. Navpopup.prototype.show = function () {
  6342.     //document.title+='s';
  6343.     if (this.noshow) { return; }
  6344.     //document.title+='t';
  6345.     this.reposition();
  6346.     WikiLook_Overlay._DIVrepositioned=false;
  6347.     this.raise();
  6348.     this.unhide();
  6349. };
  6350.  
  6351.  
  6352. /**
  6353.    Runs the {@link #show} method in a little while, unless we're
  6354.    already visible.
  6355.    @param {integer} time Delay in milliseconds
  6356.    @see #showSoonIfStable
  6357. */
  6358. Navpopup.prototype.showSoon = function (time) {
  6359.     if (this.visible) { return; }
  6360.     this.noshow=false;
  6361.     //~ We have to save the value of @tt{this} so that the closure below
  6362.     //~ works.
  6363.     var savedThis=this;
  6364.     //this.start_x = Navpopup.tracker.x;
  6365.     //this.start_y = Navpopup.tracker.y;
  6366.     setTimeout(function () {
  6367.         if (Navpopup.tracker.active) {
  6368.             savedThis.reposition.apply(savedThis, [Navpopup.tracker.x + 2, Navpopup.tracker.y + 2]);
  6369.         }
  6370.         //~ Have to use apply to invoke his member function here
  6371.         savedThis.show.apply(savedThis, []);
  6372.     }, time);
  6373. };
  6374.  
  6375. /**
  6376.    Checks to see if the mouse pointer has
  6377.    stabilised (checking every <code>time</code>/2 milliseconds) and runs the
  6378.    {@link #show} method if it has. This method makes {@link #showSoon} redundant.
  6379.    @param {integer} time The minimum time (ms) before the popup may be shown.
  6380. */
  6381. Navpopup.prototype.showSoonIfStable = function (time) {
  6382.     log ('showSoonIfStable, time='+time);
  6383.     if (this.visible) { return; }
  6384.     this.noshow = false;
  6385.  
  6386.     //~ initialize these variables so that we never run @tt{show} after
  6387.     //~ just half the time
  6388.     this.stable_x = -10000; this.stable_y = -10000;
  6389.  
  6390.     var stableShow = function() {
  6391.         log('stableShow called');
  6392.         var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y;
  6393.         var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y;
  6394.         var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz;
  6395.         //document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] ';
  6396.         if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) {
  6397.             log ('mouse is stable');
  6398.             clearInterval(savedThis.showSoonStableTimer);
  6399.             savedThis.reposition.apply(savedThis, [new_x + 7, new_y + 10]);
  6400.             savedThis.show.apply(savedThis, []);
  6401.             return;
  6402.         }
  6403.         savedThis.stable_x = new_x; savedThis.stable_y = new_y;
  6404.     };
  6405.     var savedThis = this;
  6406.     this.showSoonStableTimer = setInterval(stableShow, time/2);
  6407. };
  6408.  
  6409. /**
  6410.    Makes the popup unhidable until we call {@link #unstick}.
  6411. */
  6412. Navpopup.prototype.stick=function() {
  6413.     this.noshow=false;
  6414.     this.sticky=true;
  6415. };
  6416.  
  6417. /**
  6418.    Allows the popup to be hidden.
  6419. */
  6420. Navpopup.prototype.unstick=function() {
  6421.     this.sticky=false;
  6422. };
  6423.  
  6424. /**
  6425.    Sets the {@link #noshow} flag and hides the popup. This should be called
  6426.    when the mouse leaves the link before
  6427.    (or after) it's actually been displayed.
  6428. */
  6429. Navpopup.prototype.banish = function () {
  6430.     log ('banish called');
  6431.     // hide and prevent showing with showSoon in the future
  6432.     this.noshow=true;
  6433.     if (this.showSoonStableTimer) {
  6434.         log('clearing showSoonStableTimer');
  6435.         clearInterval(this.showSoonStableTimer);
  6436.     }
  6437.     this.hide();
  6438. };
  6439.  
  6440. /**
  6441.    Runs hooks added with {@link #addHook}.
  6442.    @private
  6443.    @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  6444.    @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
  6445. */
  6446. Navpopup.prototype.runHooks = function (key, when) {
  6447.     if (!this.hooks[key]) { return; }
  6448.     var keyHooks=this.hooks[key];
  6449.     var len=keyHooks.length;
  6450.     for (var i=0; i< len; ++i) {
  6451.         if (keyHooks[i] && keyHooks[i].when == when) {
  6452.             if (keyHooks[i].hook.apply(this, [])) {
  6453.                 // remove the hook
  6454.                 if (keyHooks[i].hookId) {
  6455.                     delete this.hookIds[keyHooks[i].hookId];
  6456.                 }
  6457.                 keyHooks[i]=null;
  6458.             }
  6459.         }
  6460.     }
  6461. };
  6462.  
  6463. /**
  6464.    Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments.
  6465.    @param {Function} hook The hook function. Functions that return true are deleted.
  6466.    @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide'
  6467.    @param {String} when Controls exactly when the hook is run: either 'before' or 'after'
  6468.    @param {String} uid A truthy string identifying the hook function; if it matches another hook in this position, it won't be added again.
  6469. */
  6470. Navpopup.prototype.addHook = function ( hook, key, when, uid ) {
  6471.     when = when || 'after';
  6472.     if (!this.hooks[key]) { return; }
  6473.     // if uid is specified, don't add duplicates
  6474.     var hookId=null;
  6475.     if (uid) {
  6476.         hookId=[key,when,uid].join('|');
  6477.         if (this.hookIds[hookId]) {
  6478.             return;
  6479.         }
  6480.         this.hookIds[hookId]=true;
  6481.     }
  6482.     this.hooks[key].push( {hook: hook, when: when, hookId: hookId} );
  6483. };
  6484.  
  6485. /**
  6486.    Creates the main DIV element, which contains all the actual popup content.
  6487.    Runs hooks with key 'create'.
  6488.    @private
  6489. */
  6490. Navpopup.prototype.createMainDiv = function () {
  6491.     if (this.mainDiv) { return; }
  6492.     this.runHooks('create', 'before');
  6493.     var mainDiv=document.createElementNS("http://www.w3.org/1999/xhtml",'div');
  6494.     
  6495.     var savedThis=this;
  6496.     mainDiv.onclick=function(e) {savedThis.onclickHandler(e);};
  6497.     mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv';
  6498.     mainDiv.id=mainDiv.className + this.uid;
  6499.     WikiLook_Overlay._divQ.unshift(mainDiv.id);
  6500.     
  6501.     mainDiv.style.position='absolute';
  6502.     mainDiv.style.display='none';
  6503.     mainDiv.className='navpopup'+WikiLook_Overlay._DIVclass;
  6504.  
  6505.     // easy access to javascript object through DOM functions
  6506.     mainDiv.navpopup=this;
  6507.  
  6508.     this.mainDiv=mainDiv;
  6509.     content.document.body.appendChild(mainDiv);
  6510.     this.runHooks('create', 'after');
  6511. };
  6512. /**
  6513.    Calls the {@link #raise} method.
  6514.    @private
  6515. */
  6516. Navpopup.prototype.onclickHandler=function(e) {
  6517.     this.raise();
  6518. };
  6519. /**
  6520.    Makes the popup draggable, using a {@link Drag} object.
  6521.    @private
  6522. */
  6523.  
  6524.  
  6525. Navpopup.prototype.makeDraggable=function(handleName) {
  6526.     if (!this.mainDiv) { this.createMainDiv(); }
  6527.     var drag=new Drag();
  6528.     if (!handleName) {
  6529.         drag.startCondition=function(e) {
  6530.         try { 
  6531.             if (e.shiftKey||e.target.href != null||e.target.toString()=='[object HTMLImageElement]'/*||e.target.toString()=="[object HTMLSpanElement]"*/) { return false; } 
  6532.         } 
  6533.         catch (err) { return false; }
  6534.         return true;
  6535.         };
  6536.     }
  6537.     var dragHandle = content.document.getElementById("dasdadcfasdf1") || this.mainDiv;
  6538.     var np=this;
  6539.     drag.endHook=function(x,y) {
  6540.         Navpopup.tracker.dirty=true;
  6541.         np.reposition(x,y);
  6542.         //this._DIVrepositioned=false;
  6543.     };
  6544.     drag.init(dragHandle,this.mainDiv);
  6545. };
  6546.  
  6547. /** Hides the popup using CSS. Runs hooks with key 'hide'.
  6548.     Sets {@link #visible} appropriately.     {@link #banish} should be called externally instead of this method.
  6549.  
  6550.     @private
  6551. */
  6552. Navpopup.prototype.hide = function () {
  6553.     this.runHooks('hide', 'before');
  6554.     this.abortDownloads();
  6555.     if (this.sticky) { return; }
  6556.     if (typeof this.visible != 'undefined' && typeof this.mainDiv != 'undefined' && this.visible) {
  6557.         try {this.mainDiv.style.display='none';} catch (e) {return};
  6558.         this.visible=false;
  6559.     }
  6560.     this.runHooks('hide', 'after');
  6561. };
  6562.  
  6563. /** Shows the popup using CSS. Runs hooks with key 'unhide'.
  6564.     Sets {@link #visible} appropriately.   {@link #show} should be called externally instead of this method.
  6565.     @private
  6566. */
  6567. Navpopup.prototype.unhide = function () {
  6568.     this.runHooks('unhide', 'before');
  6569.     if (typeof this.visible != 'undefined' && !this.visible) {
  6570.         this.mainDiv.style.display='inline';
  6571.         this.visible=true;
  6572.     }
  6573.     this.runHooks('unhide', 'after');
  6574. };
  6575.  
  6576. /**
  6577.    Sets the <code>innerHTML</code> attribute of the main div containing the popup content.
  6578.    @param {String} html The HTML to set.
  6579. */
  6580. Navpopup.prototype.setInnerHTML = function (html) {
  6581.     this.mainDiv.innerHTML = WikiLook_Overlay._CSS + html;
  6582. };
  6583.  
  6584.  
  6585. /**
  6586.    Updates the {@link #width} and {@link #height} attributes with the CSS properties.
  6587.    @private
  6588. */
  6589. Navpopup.prototype.updateDimensions = function () {
  6590.     this.width=parseInt(this.mainDiv.offsetWidth, 10);
  6591.     this.height=parseInt(this.mainDiv.offsetHeight, 10);
  6592. };
  6593.  
  6594. /**
  6595.    Checks if the point (x,y) is within {@link #fuzz} of the
  6596.    {@link #mainDiv}.
  6597.    @param {integer} x x-coordinate (px)
  6598.    @param {integer} y y-coordinate (px)
  6599.    @type boolean
  6600. */
  6601. Navpopup.prototype.isWithin = function(x,y) {
  6602.     //~ If we're not even visible, no point should be considered as
  6603.     //~ being within the popup.
  6604.     if (!this.visible) { return false; }
  6605.     this.updateDimensions();
  6606.     var fuzz=this.fuzz || 0;
  6607.     //~ Use a simple box metric here.
  6608.     return (x+fuzz >= this.left && x-fuzz <= this.left + this.width &&
  6609.         y+fuzz >= this.top  && y-fuzz <= this.top  + this.height);
  6610. };
  6611.  
  6612. /**
  6613.    Adds a download to {@link #downloads}.
  6614.    @param {Downloader} download
  6615. */
  6616. Navpopup.prototype.addDownload=function(download) {
  6617.     if (!download) { return; }
  6618.     this.downloads.push(download);
  6619. };
  6620. /**
  6621.    Aborts the downloads listed in {@link #downloads}.
  6622.    @see Downloader#abort
  6623. */
  6624. Navpopup.prototype.abortDownloads=function() {
  6625.     for(var i=0; i<this.downloads.length; ++i) {
  6626.         var d=this.downloads[i];
  6627.         if (d && d.abort) { d.abort(); }
  6628.     }
  6629.     this.downloads=[];
  6630. };
  6631.  
  6632.  
  6633. /**
  6634.    A {@link Mousetracker} instance which is a property of the constructor (pseudo-global).
  6635. */
  6636. Navpopup.tracker=new Mousetracker();
  6637. // ENDFILE: navpopup.js
  6638. // STARTFILE: diff.js
  6639. //<NOLITE>
  6640. /*
  6641.  * Javascript Diff Algorithm
  6642.  *  By John Resig (http://ejohn.org/) and [[:en:User:Lupin]]
  6643.  *
  6644.  * More Info:
  6645.  *  http://ejohn.org/projects/javascript-diff-algorithm/
  6646.  */
  6647.  
  6648. function delFmt(x) {
  6649.     if (!x.length) { return ''; }
  6650.     return "<del class='popupDiff'>" + x.join('') +"</del>";
  6651. }
  6652. function insFmt(x) {
  6653.     if (!x.length) { return ''; }
  6654.     return "<ins class='popupDiff'>" + x.join('') +"</ins>";
  6655. }
  6656.  
  6657. function countCrossings(a, b, i, eject) {
  6658.     // count the crossings on the edge starting at b[i]
  6659.     if (!b[i].row && b[i].row !== 0) { return -1; }
  6660.     var count=0;
  6661.     for (var j=0; j<a.length; ++j) {
  6662.         if (!a[j].row && a[j].row !== 0) { continue; }
  6663.         if ( (j-b[i].row)*(i-a[j].row) > 0) {
  6664.             if(eject) { return true; }
  6665.             count++;
  6666.         }
  6667.     }
  6668.     return count;
  6669. }
  6670.  
  6671. function shortenDiffString(str, context) {
  6672.     var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)');
  6673.     var splitted=str.parenSplit(re);
  6674.     var ret=[''];
  6675.     for (var i=0; i<splitted.length; i+=2) {
  6676.         if (splitted[i].length < 2*context) {
  6677.             ret[ret.length-1] += splitted[i];
  6678.             if (i+1<splitted.length) { ret[ret.length-1] += splitted[i+1]; }
  6679.             continue;
  6680.         }
  6681.         else {
  6682.             if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); }
  6683.             if (i+1 < splitted.length) {
  6684.                 ret.push(splitted[i].substring(splitted[i].length-context) +
  6685.                      splitted[i+1]);
  6686.             }
  6687.         }
  6688.     }
  6689.     while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); }
  6690.     return ret;
  6691. }
  6692.  
  6693.  
  6694. function diffString( o, n, simpleSplit ) {
  6695.     var splitRe=RegExp('([[]{2}|[\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|[*:]+|\\s|\\b)');
  6696.  
  6697.     o=o.entify(); n=n.entify();
  6698.     var out, i;
  6699.     if (simpleSplit) { out = diff( o.split(/\b/), n.split(/\b/) ); }
  6700.     else { out = diff( o.parenSplit(splitRe), n.parenSplit(splitRe) ); }
  6701.     var str = "";
  6702.     var acc=[]; // accumulator for prettier output
  6703.  
  6704.     // crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out
  6705.     // this doesn't always do things optimally but it should be fast enough
  6706.     var maxOutputPair=0;
  6707.     for (i=0; i<out.n.length; ++i) {
  6708.         if ( out.n[i].paired ) {
  6709.         if( maxOutputPair > out.n[i].row ) {
  6710.             // tangle - delete pairing
  6711.             out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text;
  6712.             out.n[i]=out.n[i].text;
  6713.         }
  6714.         if (maxOutputPair < out.n[i].row) { maxOutputPair = out.n[i].row; }
  6715.         }
  6716.     }
  6717.  
  6718.     // output the stuff preceding the first paired old line
  6719.     for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); }
  6720.     str += delFmt(acc); acc=[];
  6721.  
  6722.     // main loop
  6723.     for ( i = 0; i < out.n.length; ++i ) {
  6724.         // output unpaired new "lines"
  6725.         while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); }
  6726.         str += insFmt(acc); acc=[];
  6727.         if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line"
  6728.             str += out.n[i].text;
  6729.             // output unpaired old rows starting after this new line's partner
  6730.             var m = out.n[i].row + 1;
  6731.             while ( m < out.o.length && !out.o[m].paired ) { acc.push ( out.o[m++] ); }
  6732.             str += delFmt(acc); acc=[];
  6733.         }
  6734.     }
  6735.     return str;
  6736. }
  6737.  
  6738. // see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object
  6739. // FIXME: use obj.hasOwnProperty instead of this kludge!
  6740. window.jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' +
  6741.                    '|eval|hasOwnProperty|propertyIsEnumerable' +
  6742.                    '|to(Source|String|LocaleString)|(un)?watch|valueOf)$');
  6743. function diffBugAlert(word) {
  6744.     if (!diffBugAlert.list[word]) {
  6745.         diffBugAlert.list[word]=1;
  6746.         alert('Bad word: '+word+'\n\nPlease report this bug.');
  6747.     }
  6748. }
  6749. diffBugAlert.list={};
  6750.  
  6751. function makeDiffHashtable(src) {
  6752.     var ret={};
  6753.     for ( var i = 0; i < src.length; i++ ) {
  6754.         if ( jsReservedProperties.test(src[i]) ) { src[i] += '<!-- -->'; }
  6755.         if ( !ret[ src[i] ] ) {    ret[ src[i] ] = []; }
  6756.         try { ret[ src[i] ].push( i ); } catch (err) { diffBugAlert(src[i]); }
  6757.     }
  6758.     return ret;
  6759. }
  6760.  
  6761. function diff( o, n ) {
  6762.  
  6763.     // pass 1: make hashtable ns with new rows as keys
  6764.     var ns = makeDiffHashtable(n);
  6765.  
  6766.     // pass 2: make hashtable os with old rows as keys
  6767.     var os = makeDiffHashtable(o);
  6768.  
  6769.     // pass 3: pair unique new rows and matching unique old rows
  6770.     var i;
  6771.     for ( i in ns ) {
  6772.         if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) {
  6773.             n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true };
  6774.             o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true };
  6775.         }
  6776.     }
  6777.  
  6778.     // pass 4: pair matching rows immediately following paired rows (not necessarily unique)
  6779.     for ( i = 0; i < n.length - 1; i++ ) {
  6780.         if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired &&
  6781.              n[i+1] == o[ n[i].row + 1 ] ) {
  6782.             n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true };
  6783.             o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true };
  6784.         }
  6785.     }
  6786.  
  6787.     // pass 5: pair matching rows immediately preceding paired rows (not necessarily unique)
  6788.     for ( i = n.length - 1; i > 0; i-- ) {
  6789.         if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired &&
  6790.              n[i-1] == o[ n[i].row - 1 ] ) {
  6791.             n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true };
  6792.             o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true };
  6793.         }
  6794.     }
  6795.  
  6796.     return { o: o, n: n };
  6797. }
  6798. //</NOLITE>
  6799. // ENDFILE: diff.js
  6800. // STARTFILE: init.js
  6801. function setSiteInfo() {
  6802.     if (window.popupLocalDebug) {
  6803.         pg.wiki.hostname = 'en.wikipedia.org';
  6804.     } else {
  6805.  
  6806.         pg.wiki.hostname = WikiLook_Overlay._currentParser.substring(7, WikiLook_Overlay._currentParser.length);
  6807.     }
  6808.         pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname);
  6809.     pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname);
  6810.     pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname);
  6811.     pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null;
  6812.     pg.wiki.commonslang = pg.wiki.commons ? pg.wiki.commons.split('.')[0] : null;
  6813.     pg.wiki.lang = pg.wiki.hostname.split('.')[0];
  6814.     // toolDbName needs pg.wiki.lang and pg.wiki.hostname
  6815.     pg.wiki.prePath='';
  6816.     if (pg.wiki.hostname == 'secure.wikimedia.org') {
  6817.         var s=document.location.href.split('/');
  6818.         pg.wiki.prePath=s.slice(3,5).join('/');
  6819.         pg.wiki.lang=s[4];
  6820.     }
  6821.     var port = location.port ? ':' + location.port : '';
  6822.     pg.wiki.sitebase = joinPath([pg.wiki.hostname + port, pg.wiki.prePath]);
  6823. }
  6824.  
  6825. function getArticlePath() {
  6826.     if (isFunction(window.siteArticlePath)) {
  6827.         return siteArticlePath();
  6828.     }
  6829.     return 'wiki';
  6830. }
  6831.  
  6832. function getBotInterfacePath() {
  6833.     if (isFunction(window.siteBotInterfacePath)) {
  6834.         return siteBotInterfacePath();
  6835.     }
  6836.     var botInterfacePath = pg.wiki.articlePath.replace(/\/index[.]php$/, '');
  6837.     if (pg.wiki.wikimedia) { botInterfacePath = 'w'; } // as in http://some.thing.com/w/index.php?title=foo
  6838.     else if (pg.wiki.wikia) { botInterfacePath = ''; }
  6839.     return botInterfacePath;
  6840. }
  6841.  
  6842. function setTitleBase() {
  6843.     var protocol = ( window.popupLocalDebug ? 'http:' : 'http:' );
  6844.     pg.wiki.articlePath = getArticlePath();  // as in http://some.thing.com/wiki/Article
  6845.     pg.wiki.botInterfacePath = getBotInterfacePath();
  6846.     // default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo
  6847.  
  6848.     var titletail = joinPath([pg.wiki.botInterfacePath, 'index.php?title=']);
  6849.     var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']);
  6850.  
  6851.     // other sites may need to add code here to set titletail depending on how their urls work
  6852.  
  6853.     pg.wiki.titlebase   = protocol + '//' + joinPath([pg.wiki.sitebase, titletail]);
  6854.     pg.wiki.titlebase2  = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]);
  6855.     pg.wiki.wikibase    = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.botInterfacePath]);
  6856.     pg.wiki.articlebase = protocol + '//' + joinPath([pg.wiki.sitebase, pg.wiki.articlePath]);
  6857.     pg.wiki.commonsbase = protocol + '//' + joinPath([pg.wiki.commons, pg.wiki.botInterfacePath]);
  6858.     pg.re.basenames = RegExp( '^(' +
  6859.                   map( literalizeRegex, [ pg.wiki.titlebase, pg.wiki.titlebase2,
  6860.                               pg.wiki.articlebase ]).join('|') + ')' );
  6861. }
  6862.  
  6863.  
  6864. //////////////////////////////////////////////////
  6865. // Global regexps
  6866.  
  6867. function setMainRegex() {
  6868.     var reStart='[^:]*://';
  6869.     var preTitles = joinPath([literalizeRegex(pg.wiki.botInterfacePath), '(?:index[.]php|wiki[.]phtml)[?]title=']);
  6870.     // slightly ugly hack when pg.wiki.articlePath is empty
  6871.     preTitles += '|' + literalizeRegex( ( pg.wiki.articlePath ? pg.wiki.articlePath + '/' : ''));
  6872.  
  6873.     var reEnd='/(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?';
  6874.     pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd);
  6875. }
  6876.  
  6877. function setRegexps() {
  6878.     setMainRegex();
  6879.     var sp=nsRe('Special');
  6880.     pg.re.urlNoPopup=RegExp('((title=|/)' + sp +  '(?:%3A|:)|section=[0-9])') ;
  6881.     pg.re.contribs  =RegExp('(title=|/)'  + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + pg.ns.user+':)(.*)') ;
  6882.     pg.re.email     =RegExp('(title=|/)'  + sp + '(?:%3A|:)Emailuser'     + '(&target=|/|/(?:' + pg.ns.user+':)?)(.*)') ;
  6883.     pg.re.backlinks =RegExp('(title=|/)'  + sp + '(?:%3A|:)Whatlinkshere' + '(&target=|/)([^&]*)');
  6884.  
  6885. //<NOLITE>
  6886.     var im=nsReImage();
  6887.     // note: tries to get images in infobox templates too, e.g. movie pages, album pages etc
  6888.     //                      (^|\[\[)image: *([^|\]]*[^|\] ]) *
  6889.     //                      (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)?
  6890.     //                                                        $4 = 120 as in 120px
  6891.     pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' +
  6892.                  '([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' +
  6893.                  '(' + getValueOf('popupImageVarsRegexp') + ')' +
  6894.                  ' *= *(?:\\[\\[ *)?(?:' + im + ':)?' +
  6895.                  '([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ;
  6896.     pg.re.imageBracketCount = 6;
  6897.  
  6898.     pg.re.category = RegExp('\\[\\[' +nsRe('Category') +
  6899.                 ': *([^|\\]]*[^|\\] ]) *', 'i');
  6900.     pg.re.categoryBracketCount = 1;
  6901.  
  6902.     pg.re.ipUser=RegExp('('+nsRe('User')+':)?' +
  6903.                 '((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' +
  6904.                 '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])');
  6905.  
  6906.     pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im');
  6907.     pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im');
  6908.  
  6909. //</NOLITE>
  6910.     // FIXME replace with general parameter parsing function, this is daft
  6911.     pg.re.oldid=RegExp('[?&]oldid=([^&]*)');
  6912.     pg.re.diff=RegExp('[?&]diff=([^&]*)');
  6913. }
  6914.  
  6915.  
  6916. //<NOLITE>
  6917. //////////////////////////////////////////////////
  6918. // Image sources
  6919.  
  6920. function setImageSources() {
  6921.     pg.wiki.imageSources=[];
  6922.  
  6923.     // frequently seen thumbs
  6924.     pg.wiki.imageSources.push(
  6925.     {wiki: pg.wiki.hostname, thumb: true,  width: 250}, // default
  6926.     {wiki: pg.wiki.hostname, thumb: true,  width: 250} // gallery
  6927.         );
  6928.  
  6929.     // frequently seen thumbs on commons
  6930.     if (pg.wiki.commons) {
  6931.         pg.wiki.imageSources.push(
  6932.         {wiki: pg.wiki.commons, thumb: true,  width: 250},
  6933.         {wiki: pg.wiki.commons, thumb: true,  width: 250}
  6934.             );
  6935.     }
  6936.  
  6937.     // unusual thumb sizes and full-size
  6938.     pg.wiki.imageSources.push(
  6939.     {wiki: pg.wiki.hostname, thumb: true,  width: 200}, // common?
  6940.     {wiki: pg.wiki.hostname, thumb: true,  width: 250}, // common?
  6941.     {wiki: pg.wiki.hostname, thumb: true,  width: 300},
  6942.     {wiki: pg.wiki.hostname, thumb: true,  width: 210},
  6943.     {wiki: pg.wiki.hostname, thumb: true,  width: 230},
  6944.     {wiki: pg.wiki.hostname, thumb: false, width: 0} // no comma
  6945.         );
  6946.  
  6947.     // full-size on commons
  6948.     if (pg.wiki.commons) {
  6949.         pg.wiki.imageSources.push({wiki: pg.wiki.commons, thumb: false, width: 0});
  6950.     }
  6951. }
  6952. //</NOLITE>
  6953.  
  6954. //////////////////////////////////////////////////
  6955. // miscellany
  6956.  
  6957. function setupCache() {
  6958.     // page caching
  6959.     pg.cache.pages = [];
  6960.     pg.cache.images = [];
  6961.  
  6962.     // global array for 404'ed image urls
  6963.     pg.cache.badImageUrls=[];
  6964. }
  6965.  
  6966. function setMisc() {
  6967.     pg.current.link=null;
  6968.     pg.current.links=[];
  6969.     pg.current.linksHash={};
  6970.  
  6971.     // downloading images are put here
  6972.     pg.misc.imageArray=[];
  6973.  
  6974.     setupCache();
  6975.     // FIXME what is this for?
  6976.     pg.misc.gImage=null; // global for image
  6977.  
  6978.     // check to see if images are done with this timer
  6979.     pg.timer.image=null;
  6980.  
  6981.     // These are for checkImages()
  6982.     pg.counter.checkImages=0;
  6983.     pg.timer.checkImages=null;
  6984.     pg.timer.checkPopupPosition=null;
  6985.     pg.counter.loop=0;
  6986.  
  6987.     // ids change with each popup: popupImage0, popupImage1 etc
  6988.     pg.idNumber=0;
  6989.  
  6990.     // for myDecodeURI
  6991.     pg.misc.decodeExtras = [
  6992.         {from: '%2C', to: ',' },
  6993.         {from: '_',   to: ' ' },
  6994.         {from: '%24', to: '$'},
  6995.         {from: '%26',   to: '&' } // no ,
  6996.         ];
  6997.  
  6998. }
  6999.  
  7000. function leadingInteger(s){
  7001.     var n=s.match(/^(\d*)/)[1];
  7002.     if (n) { return +n; }
  7003.     return null;
  7004. }
  7005.  
  7006. function setBrowserHacks() {
  7007.     var useOriginal=false;
  7008.     // browser-specific hacks
  7009.     if (typeof window.opera != 'undefined') {
  7010.         //if (leadingInteger(opera.version()) < 9)
  7011.         { useOriginal=true; } // v9 beta still seems to have buggy css
  7012.         setDefault('popupNavLinkSeparator', ' · ');
  7013.     } else if (navigator.appName=='Konqueror') {
  7014.         setDefault('popupNavLinkSeparator', ' • ');
  7015.         pg.flag.isKonq=true;
  7016.     } else if ( navigator.vendor && navigator.vendor.toLowerCase().indexOf('apple computer')===0) {
  7017.         pg.flag.isSafari=true;
  7018.         var webkit=+navigator.userAgent.replace(RegExp('^.*AppleWebKit[/](\\d+).*', 'i'), '$1');
  7019.         if (webkit < 420) { useOriginal=true; }
  7020.     } else if (navigator.appName.indexOf("Microsoft")!=-1) {
  7021.         setDefault('popupNavLinkSeparator', ' · ');
  7022.         useOriginal=true;
  7023.         var ver=+navigator.userAgent.replace(RegExp('^.*MSIE (\\d+).*'), '$1');
  7024.         pg.flag.isIE=true;
  7025.         pg.flag.IEVersion=ver;
  7026.     }
  7027.     if (pg.flag.isIE && pg.flag.IEVersion < 7 || pg.flag.isKonq || webkit < 420 ) {
  7028.         pg.flag.linksLikeIE6=true;
  7029.     }
  7030.     if (useOriginal && pg.structures.original) {
  7031.         setDefault('popupStructure','original');
  7032.     }
  7033. }
  7034.  
  7035. function setupPopups() {
  7036.     // NB translatable strings should be set up first (strings.js)
  7037.     // basics
  7038.     setupDebugging();
  7039.     setSiteInfo();
  7040.     setTitleBase();
  7041.     setOptions(); // see options.js
  7042.  
  7043.     // namespaces etc
  7044.     setNamespaces();
  7045.     setInterwiki();
  7046.  
  7047.     // regexps
  7048.     setRegexps();
  7049.     setRedirs();
  7050.  
  7051.     // other stuff
  7052.     window.setImageSources && setImageSources();
  7053.     setBrowserHacks();
  7054.     setMisc();
  7055.     setupLivePreview();
  7056.  
  7057.     // main deal here
  7058.     setupTooltips();
  7059.     Navpopup.tracker.enable();
  7060.  
  7061.     setupPopups.completed = true;
  7062. }
  7063.  
  7064. // ENDFILE: init.js
  7065. // STARTFILE: navlinks.js
  7066. //<NOLITE>
  7067. //////////////////////////////////////////////////
  7068. // navlinks... let the fun begin
  7069. //
  7070.  
  7071. function defaultNavlinkSpec() {
  7072.     var str='';
  7073.     str += '<b><<mainlink|shortcut= >></b>';
  7074.     if (getValueOf('popupLastEditLink')) {
  7075.         str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}';
  7076.     }
  7077.  
  7078.     // user links
  7079.     // contribs - log - count - email - block
  7080.     // count only if applicable; block only if popupAdminLinks
  7081.     str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>';
  7082.     str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}';
  7083.     str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}';
  7084.  
  7085.     // editing links
  7086.     // talkpage   -> edit|new - history - un|watch - article|edit
  7087.     // other page -> edit - history - un|watch - talk|edit|new
  7088.     var editstr='<<edit|shortcut=e>>';
  7089.     var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'
  7090.         var historystr='<<history|shortcut=h>>if(mainspace_en){|<<editors|shortcut=E|>>}';
  7091.     var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
  7092.  
  7093.     str+='<br>if(talk){' +
  7094.         editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' +
  7095.         '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' +
  7096.         '}else{' + // not a talk page
  7097.         editOldidStr + '*' + historystr + '*' + watchstr + '*' +
  7098.         '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
  7099.         + '}';
  7100.  
  7101.     // misc links
  7102.     str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>';
  7103.  
  7104.     // admin links
  7105.     str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' +
  7106.         '<<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>>}';
  7107.     return str;
  7108. }
  7109.  
  7110. function navLinksHTML (article, hint, params) { //oldid, rcid) {
  7111.     var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>';
  7112.     // BAM
  7113.     return navlinkStringToHTML(str, article, params);
  7114. }
  7115.  
  7116. function expandConditionalNavlinkString(s,article,z,recursionCount) {
  7117.     var oldid=z.oldid, rcid=z.rcid, diff=z.diff;
  7118.     // nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out)
  7119.     if (typeof recursionCount!=typeof 0) { recursionCount=0; }
  7120.     var conditionalSplitRegex=RegExp(
  7121.         //(1     if    \\(    (2    2)    \\)      {(3    3)}  (4   else      {(5     5)}  4)1)
  7122.         '(;?\\s*if\\s*\\(\\s*([\\w]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', 'i');
  7123.     var splitted=s.parenSplit(conditionalSplitRegex);
  7124.     // $1: whole conditional
  7125.     // $2: test condition
  7126.     // $3: true expansion
  7127.     // $4: else clause (possibly empty)
  7128.     // $5: false expansion (possibly null)
  7129.     var numParens=5;
  7130.     var ret = splitted[0];
  7131.     for (var i=1; i<splitted.length; i=i+numParens+1) {
  7132.  
  7133.         var testString=splitted[i+2-1];
  7134.         var trueString=splitted[i+3-1];
  7135.         var falseString=splitted[i+5-1];
  7136.         if (typeof falseString=='undefined' || !falseString) { falseString=''; }
  7137.         var testResult=null;
  7138.  
  7139.         switch (testString) {
  7140.         case 'user':
  7141.             testResult=(article.userName())?true:false;
  7142.             break;
  7143.         case 'talk':
  7144.             testResult=(article.talkPage())?false:true; // talkPage converts _articles_ to talkPages
  7145.             break;
  7146.         case 'admin':
  7147.             testResult=getValueOf('popupAdminLinks')?true:false;
  7148.             break;
  7149.         case 'oldid':
  7150.             testResult=(typeof oldid != 'undefined' && oldid)?true:false;
  7151.             break;
  7152.         case 'rcid':
  7153.             testResult=(typeof rcid != 'undefined' && rcid)?true:false;
  7154.             break;
  7155.         case 'ipuser':
  7156.             testResult=(article.isIpUser())?true:false;
  7157.             break;
  7158.         case 'mainspace_en':
  7159.             testResult=isInMainNamespace(article) &&
  7160.                 pg.wiki.hostname=='en.wikipedia.org';
  7161.             break;
  7162.         case 'wikimedia':
  7163.             testResult=(pg.wiki.wikimedia) ? true : false;
  7164.             break;
  7165.         case 'diff':
  7166.             testResult=(typeof diff != 'undefined' && diff)?true:false;
  7167.             break;
  7168.         }
  7169.  
  7170.         switch(testResult) {
  7171.         case null: ret+=splitted[i];  break;
  7172.         case true: ret+=trueString;   break;
  7173.         case false: ret+=falseString; break;
  7174.         }
  7175.  
  7176.         // append non-conditional string
  7177.         ret += splitted[i+numParens];
  7178.     }
  7179.     if (conditionalSplitRegex.test(ret) && recursionCount < 10) {
  7180.         return expandConditionalNavlinkString(ret,article,z,recursionCount+1);
  7181.     }
  7182.     return ret;
  7183. }
  7184.  
  7185. function navlinkStringToArray(s, article, params) {
  7186.     s=expandConditionalNavlinkString(s,article,params);
  7187.     var splitted=s.parenSplit(RegExp('<<(.*?)>>'));
  7188.     var ret=[];
  7189.     for (var i=0; i<splitted.length; ++i) {
  7190.         if (i%2) { // i odd, so s is a tag
  7191.             var t=new navlinkTag();
  7192.             var ss=splitted[i].split('|');
  7193.             t.id=ss[0];
  7194.             for (var j=1; j<ss.length; ++j) {
  7195.                 var sss=ss[j].split('=');
  7196.                 if (sss.length>1) {
  7197.                     t[sss[0]]=sss[1];
  7198.                 }
  7199.                 else { // no assignment (no "="), so treat this as a title (overwriting the last one)
  7200.                     t.text=popupString(sss[0]);
  7201.                 }
  7202.             }
  7203.             t.article=article;
  7204.             var oldid=params.oldid, rcid=params.rcid, diff=params.diff;
  7205.             if (typeof oldid != 'undefined' && oldid != null) { t.oldid=oldid; }
  7206.             if (typeof rcid != 'undefined' && rcid != null) { t.rcid=rcid; }
  7207.             if (typeof diff != 'undefined' && diff != null) { t.diff=diff; }
  7208.             if (!t.text && t.id != 'mainlink') { t.text=popupString(t.id); }
  7209.             ret.push(t);
  7210.         }
  7211.         else { // plain HTML
  7212.             ret.push(splitted[i]);
  7213.         }
  7214.     }
  7215.     return ret;
  7216. }
  7217.  
  7218.  
  7219. function navlinkSubstituteHTML(s) {
  7220.     return s.split('*').join(getValueOf('popupNavLinkSeparator'))
  7221.         .split('<menurow>').join('<li class="popup_menu_row">')
  7222.         .split('</menurow>').join('</li>')
  7223.         .split('<menu>').join('<ul class="popup_menu">')
  7224.         .split('</menu>').join('</ul>');
  7225.  
  7226. }
  7227.  
  7228. function navlinkDepth(magic,s) {
  7229.     return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length;
  7230. }
  7231.  
  7232.  
  7233. // navlinkString: * becomes the separator
  7234. //                <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz'
  7235. //                                      and visible text 'fubar'
  7236. //                if(test){...} and if(test){...}else{...} work too (nested ok)
  7237.  
  7238. function navlinkStringToHTML(s,article,params) {
  7239.     //limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article));
  7240.     var p=navlinkStringToArray(s,article,params);
  7241.     var html='';
  7242.     var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it
  7243.     var menurowdepth = 0;
  7244.     var wrapping = null;
  7245.     for (var i=0; i<p.length; ++i) {
  7246.         if (typeof p[i] == typeof '') {
  7247.             html+=navlinkSubstituteHTML(p[i]);
  7248.             menudepth += navlinkDepth('menu', p[i]);
  7249.             menurowdepth += navlinkDepth('menurow', p[i]);
  7250. //            if (menudepth === 0) {
  7251. //                tagType='span';
  7252. //            } else if (menurowdepth === 0) {
  7253. //                tagType='li';
  7254. //            } else {
  7255. //                tagType = null;
  7256. //            }
  7257.         } else if (typeof p[i].type != 'undefined' && p[i].type=='navlinkTag') {
  7258.             if (menudepth > 0 && menurowdepth === 0) {
  7259.                 html += '<li class="popup_menu_item">' + p[i].html() + '</li>';
  7260.             } else {
  7261.                 html+=p[i].html();
  7262.             }
  7263.         }
  7264.     }
  7265.     return html;
  7266. }
  7267.  
  7268. function navlinkTag() {
  7269.     this.type='navlinkTag';
  7270. }
  7271.  
  7272. navlinkTag.prototype.html=function () {
  7273.     this.getNewWin();
  7274.     this.getPrintFunction();
  7275.     var html='';
  7276.     var opening, closing;
  7277.     var tagType='span';
  7278.     if (!tagType) {
  7279.         opening = ''; closing = '';
  7280.     } else {
  7281.         opening = '<' + tagType + ' class="popup_' + this.id + '">';
  7282.         closing = '</' + tagType + '>';
  7283.     }
  7284.     if (typeof this.print!='function') {
  7285.         errlog ('Oh dear - invalid print function for a navlinkTag, id='+this.id);
  7286.     } else {
  7287.         html=this.print(this);
  7288.         if (typeof html != typeof '') {html='';}
  7289.         else if (typeof this.shortcut!='undefined') html=addPopupShortcut(html, this.shortcut);
  7290.     }
  7291.     return opening + html + closing;
  7292. };
  7293.  
  7294. navlinkTag.prototype.getNewWin=function() {
  7295.     getValueOf('popupLinksNewWindow');
  7296.     if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { this.newWin=null; }
  7297.     this.newWin=pg.option.popupLinksNewWindow[this.id];
  7298. }
  7299.  
  7300. navlinkTag.prototype.getPrintFunction=function() { //think about this some more
  7301.     // this.id and this.article should already be defined
  7302.     if (typeof this.id!=typeof '' || typeof this.article!=typeof {} ) { return; }
  7303.     var html='';
  7304.     var a,t;
  7305.  
  7306.     this.noPopup=1;
  7307.     switch (this.id) {
  7308.     case 'contribs': case 'history': case 'whatLinksHere':
  7309.     case 'userPage': case 'monobook': case 'userTalk':
  7310.     case 'talk': case 'article': case 'lastEdit':
  7311.         this.noPopup=null;
  7312.     }
  7313.     switch (this.id) {
  7314.     case 'email':     case 'contribs':  case 'block':     case 'unblock':
  7315.     case 'userlog':   case 'userSpace': case 'deletedContribs':
  7316.         this.article=this.article.userName();
  7317.     }
  7318.  
  7319.     switch (this.id) {
  7320.     case 'userTalk': case 'newUserTalk': case 'editUserTalk':
  7321.     case 'userPage': case 'monobook': case 'editMonobook': case 'blocklog':
  7322.         this.article=this.article.userName(true);
  7323.     // fall through; no break
  7324.     case 'pagelog': case 'deletelog': case 'protectlog':
  7325.     delete this.oldid;
  7326.     }
  7327.  
  7328.     if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); }
  7329.  
  7330.     if (this.id != 'mainlink') {
  7331.         // FIXME anchor handling should be done differently with Title object
  7332.         this.article=this.article.removeAnchor();
  7333.         // if (typeof this.text=='undefined') this.text=popupString(this.id);
  7334.     }
  7335.  
  7336.     switch (this.id) {
  7337.     case 'undelete':       this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break;
  7338.     case 'whatLinksHere':  this.print=specialLink; this.specialpage='Whatlinkshere'; break;
  7339.     case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break;
  7340.     case 'move':           this.print=specialLink; this.specialpage='Movepage'; break;
  7341.     case 'contribs':       this.print=specialLink; this.specialpage='Contributions'; break;
  7342.     case 'deletedContribs':this.print=specialLink; this.specialpage='Deletedcontributions'; break;
  7343.     case 'email':          this.print=specialLink; this.specialpage='Emailuser'; break;
  7344.     case 'block':          this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break;
  7345.     case 'unblock':        this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break;
  7346.     case 'userlog':        this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break;
  7347.     case 'blocklog':       this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break;
  7348.     case 'pagelog':        this.print=specialLink; this.specialpage='Log'; this.sep='&page='; break;
  7349.     case 'protectlog':     this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break;
  7350.     case 'deletelog':      this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break;
  7351.     case 'userSpace':      this.print=specialLink; this.specialpage='Prefixindex'; this.sep='&namespace=2&prefix='; break;
  7352.     case 'search':         this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;
  7353.     case 'history': case 'historyfeed': case 'unwatch': case 'watch':
  7354.     case 'unprotect': case 'protect':
  7355.     this.print=wikiLink; this.action=this.id; break;
  7356.  
  7357.     case 'delete':
  7358.     this.print=wikiLink; this.action='delete';
  7359.     if (this.article.namespace()==pg.ns.image) {
  7360.         var img=this.article.stripNamespace();
  7361.         this.action+='&image='+img;
  7362.     }
  7363.     break;
  7364.  
  7365.     case 'markpatrolled':
  7366.     case 'edit': // editOld should keep the oldid, but edit should not.
  7367.     delete this.oldid; // fall through
  7368.     case 'view': case 'purge': case 'render':
  7369.     this.print=wikiLink;
  7370.     this.action=this.id; break;
  7371.     case 'raw':
  7372.     this.print=wikiLink; this.action='raw&ctype=text/css'; break;
  7373.     case 'new':
  7374.     this.print=wikiLink; this.action='edit§ion=new'; break;
  7375.     case 'mainlink':
  7376.     if (typeof this.text=='undefined') { this.text=this.article.toString().entify(); }
  7377.     if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) {
  7378.         var s=this.text.split('/'); this.text=s[s.length-1];
  7379.         if (this.text=='' && s.length > 1) { this.text=s[s.length-2]; }
  7380.     }
  7381.     this.print=titledWikiLink;
  7382.     if (typeof this.title=='undefined' && pg.current.link && typeof pg.current.link.href != 'undefined') {
  7383.         this.title=safeDecodeURI((pg.current.link.originalTitle)?pg.current.link.originalTitle:this.article);
  7384.         if (typeof this.oldid != 'undefined' && this.oldid) {
  7385.         this.title=tprintf('Revision %s of %s', [this.oldid, this.title]);
  7386.         }
  7387.     }
  7388.     this.action='view'; break;
  7389.     case 'userPage':
  7390.     case 'article':
  7391.     case 'monobook':
  7392.     case 'editMonobook':
  7393.     case 'editArticle':
  7394.     delete this.oldid;
  7395.     //alert(this.id+'\n'+this.article + '\n'+ typeof this.article);
  7396.     this.article=this.article.articleFromTalkOrArticle();
  7397.     //alert(this.id+'\n'+this.article + '\n'+ typeof this.article);
  7398.     this.print=wikiLink;
  7399.     if (this.id.indexOf('edit')==0) {
  7400.         this.action='edit';
  7401.     } else { this.action='view';}
  7402.     break;
  7403.     case 'userTalk':
  7404.     case 'talk':
  7405.     this.article=this.article.talkPage();
  7406.     delete this.oldid;
  7407.     this.print=wikiLink;
  7408.     this.action='view'; break;
  7409.     case 'arin':
  7410.     this.print=arinLink; break;
  7411.     case 'count':
  7412.     this.print=editCounterLink; break;
  7413.     case 'google':
  7414.     this.print=googleLink; break;
  7415.     case 'editors':
  7416.     this.print=editorListLink; break;
  7417.     case 'globalsearch':
  7418.     this.print=globalSearchLink; break;
  7419.     case 'lastEdit':
  7420.     this.print=titledDiffLink;
  7421.     this.title=popupString('Show the last edit');
  7422.     this.from='prev'; this.to='cur'; break;
  7423.     case 'oldEdit':
  7424.     this.print=titledDiffLink;
  7425.     this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid;
  7426.     this.from='prev'; this.to=this.oldid; break;
  7427.     case 'editOld':
  7428.     this.print=wikiLink; this.action='edit'; break;
  7429.     case 'undo':
  7430.     this.print=wikiLink; this.action='edit&undo='; break;
  7431.     case 'markpatrolled':
  7432.     this.print=wikiLink; this.action='markpatrolled';
  7433.     case 'revert':
  7434.     this.print=wikiLink; this.action='revert'; break;
  7435.     case 'nullEdit':
  7436.     this.print=wikiLink; this.action='nullEdit'; break;
  7437.     case 'diffCur':
  7438.     this.print=titledDiffLink;
  7439.     this.title=tprintf('Show changes since revision %s', [this.oldid]);
  7440.     this.from=this.oldid; this.to='cur'; break;
  7441.     case 'editUserTalk':
  7442.     case 'editTalk':
  7443.     delete this.oldid;
  7444.     this.article=this.article.talkPage();
  7445.     this.action='edit'; this.print=wikiLink; break;
  7446.     case 'newUserTalk':
  7447.     case 'newTalk':
  7448.     this.article=this.article.talkPage();
  7449.     this.action='edit§ion=new'; this.print=wikiLink; break;
  7450.     case 'lastContrib':
  7451.     case 'sinceMe':
  7452.     this.print=magicHistoryLink;
  7453.     break;
  7454.     case 'togglePreviews':
  7455.     this.text=popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews');
  7456.     case 'disablePopups': case 'purgePopups':
  7457.     this.print=popupMenuLink;
  7458.     break;
  7459.     default:
  7460.     this.print=function () {return 'Unknown navlink type: '+this.id+''};
  7461.     }
  7462. };
  7463. //
  7464. //  end navlinks
  7465. //////////////////////////////////////////////////
  7466. //</NOLITE>
  7467. // ENDFILE: navlinks.js
  7468. // STARTFILE: shortcutkeys.js
  7469. //<NOLITE>
  7470. function popupHandleKeypress(evt) {
  7471.     var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which);
  7472.     if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { return; }
  7473.     if (keyCode==27) { // escape
  7474.         if (WikiLook_Overlay._divQ[0]!=null) {
  7475.             WikiLook_Overlay.removeDivPrp(WikiLook_Overlay._divQ[0]);
  7476.             //WikiLook_Overlay._currentDoc.body.removeChild(WikiLook_Overlay._currentDoc.getElementById(WikiLook_Overlay._divQ[0]));
  7477.             WikiLook_Overlay._divQ.splice(0,1);
  7478.             return; // swallow keypress
  7479.         } 
  7480.     }
  7481.  
  7482.     var letter=String.fromCharCode(keyCode);
  7483.     var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A');
  7484.     var startLink=0;
  7485.     var i,j;
  7486.  
  7487.     if (popupHandleKeypress.lastPopupLinkSelected) {
  7488.         for (i=0; i<links.length; ++i) {
  7489.             if (links[i]==popupHandleKeypress.lastPopupLinkSelected) { startLink=i; }
  7490.         }
  7491.     }
  7492.     for (j=0; j<links.length; ++j) {
  7493.         i=(startLink + j + 1) % links.length;
  7494.         if (links[i].getAttribute('popupkey')==letter) {
  7495.             if (evt && evt.preventDefault) evt.preventDefault();
  7496.             links[i].focus();
  7497.             popupHandleKeypress.lastPopupLinkSelected=links[i];
  7498.             return false; // swallow keypress
  7499.         }
  7500.     }
  7501.  
  7502.     // pass keypress on
  7503.     try {if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); } } catch(err)  { document.oldPopupOnkeypress=null}
  7504.     return true;
  7505. }
  7506.  
  7507. function addPopupShortcuts() {
  7508.     if (document.onkeypress!=popupHandleKeypress) {
  7509.         document.oldPopupOnkeypress=document.onkeypress;
  7510.     }
  7511.     document.onkeypress=popupHandleKeypress;
  7512. }
  7513.  
  7514. function rmPopupShortcuts() {
  7515.     popupHandleKeypress.lastPopupLinkSelected=null;
  7516.     try {
  7517.         if (document.oldPopupOnkeypress && document.oldPopupOnkeypress==popupHandleKeypress) {
  7518.             // panic
  7519.             document.onkeypress=null; //function () {};
  7520.             return;
  7521.         }
  7522.         document.onkeypress=document.oldPopupOnkeypress;
  7523.     } catch (nasties) { /* IE goes here */ }
  7524. }
  7525.  
  7526.  
  7527. function addLinkProperty(html, property) {
  7528.     // take "<a href=...>...</a> and add a property
  7529.     // not sophisticated at all, easily broken
  7530.     var i=html.indexOf('>');
  7531.     if (i<0) { return html; }
  7532.     return html.substring(0,i) + ' ' + property + html.substring(i);
  7533. }
  7534.  
  7535. function addPopupShortcut(html, key) {
  7536.     if (!getValueOf('popupShortcutKeys')) { return html; }
  7537.     var ret= addLinkProperty(html, 'popupkey="'+key+'"');
  7538.     if (key==' ') { key=popupString('spacebar'); }
  7539.     return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4');
  7540. }
  7541. //</NOLITE>
  7542. // ENDFILE: shortcutkeys.js
  7543. // STARTFILE: diffpreview.js
  7544. //<NOLITE>
  7545. function loadDiff(article, oldid, diff, navpop) {
  7546.     navpop.diffData={};
  7547.     var oldRev, newRev;
  7548.     switch (diff) {
  7549.     case 'cur':
  7550.         switch ( oldid ) {
  7551.         case null:
  7552.         case '':
  7553.         case 'prev':
  7554.             // eg newmessages diff link
  7555.             oldRev='0&direction=prev';
  7556.             newRev=0;
  7557.             break;
  7558.         default:
  7559.             oldRev = oldid;
  7560.             newRev = 0;
  7561.         }
  7562.         break;
  7563.     case 'prev':
  7564.         oldRev = ( oldid || 0 ) + '&direction=prev'; newRev = oldid; break;
  7565.     case 'next':
  7566.         oldRev = oldid; newRev = oldid + '&direction=next';
  7567.         break;
  7568.     default:
  7569.         oldRev = oldid || 0; newRev = diff || 0; break;
  7570.     }
  7571.     oldRev = oldRev || 0;
  7572.     newRev = newRev || 0;
  7573.  
  7574.     var go = function() {
  7575.         pendingNavpopTask(navpop);
  7576.         getWiki(article, doneDiffNew, newRev, navpop);
  7577.  
  7578.         pendingNavpopTask(navpop);
  7579.         getWiki(article, doneDiffOld, oldRev, navpop);
  7580.  
  7581.         var tz = Cookie.read('popTz');
  7582.         if ( (window.wgEnableAPI || wgEnableAPI) && getValueOf('popupAdjustDiffDates') && tz===null) {
  7583.             pendingNavpopTask(navpop);
  7584.             getPageWithCaching(pg.wiki.wikibase + '/api.php?format=json&action=query&meta=userinfo&uiprop=options',
  7585.                        function(d) {
  7586.                            completedNavpopTask(navpop);
  7587.                            setTimecorrectionCookie(d);
  7588.                            if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }
  7589.                        },  navpop);
  7590.         }
  7591.         return true; // remove hook once run
  7592.     }
  7593.     if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); }
  7594.     else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); }
  7595. }
  7596.  
  7597. function setTimecorrectionCookie(d) {
  7598.     try {
  7599.         var jsobj=getJsObj(d.data);
  7600.         var tz=jsobj.query.userinfo.options.timecorrection;
  7601.     } catch (someError) {
  7602.         logerr( 'setTimecorretion failed' );
  7603.         return;
  7604.     }
  7605.     Cookie.create( 'popTz', getTimeOffset(tz), 1);
  7606. }
  7607.  
  7608. function doneDiff(download, isOld) {
  7609.     if (!download.owner || !download.owner.diffData) { return; }
  7610.     var navpop=download.owner;
  7611.     var label= (isOld) ? 'Old' : 'New';
  7612.     var otherLabel=(isOld) ? 'New' : 'Old';
  7613.     navpop.diffData[label]=download;
  7614.     completedNavpopTask(download.owner);
  7615.     if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }
  7616. }
  7617.  
  7618. function diffDownloadsComplete(navpop) {
  7619.     if ( Cookie.read('popTz')===null) { return false; }
  7620.     return navpop.diffData.Old && navpop.diffData.New;
  7621. }
  7622.  
  7623. function doneDiffNew(download) { doneDiff(download, false); }
  7624. function doneDiffOld(download) { doneDiff(download, true);  }
  7625.  
  7626. function rmBoringLines(a,b,context) {
  7627.  
  7628.     if (typeof context == 'undefined') { context=2; }
  7629.     // this is fairly slow... i think it's quicker than doing a word-based diff from the off, though
  7630.     var aa=[], aaa=[];
  7631.     var bb=[], bbb=[];
  7632.     var i, j;
  7633.  
  7634.     // first, gather all disconnected nodes in a and all crossing nodes in a and b
  7635.     for (i=0; i<a.length; ++i ) {
  7636.         if(!a[i].paired) { aa[i]=1; }
  7637.         else if (countCrossings(b,a,i, true)) {
  7638.             aa[i]=1;
  7639.             bb[ a[i].row ] = 1;
  7640.         }
  7641.     }
  7642.  
  7643.     // pick up remaining disconnected nodes in b
  7644.     for (i=0; i<b.length; ++i ) {
  7645.         if (bb[i]==1) { continue; }
  7646.         if(!b[i].paired) { bb[i]=1; }
  7647.     }
  7648.  
  7649.     // another pass to gather context: we want the neighbours of included nodes which are not yet included
  7650.     // we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass
  7651.     for (i=0; i<b.length; ++i) {
  7652.         if ( bb[i] == 1 ) {
  7653.             for (j=max(0,i-context); j < min(b.length, i+context); ++j) {
  7654.                 if ( !bb[j] ) { bb[j] = 1; aa[ b[j].row ] = 0.5; }
  7655.             }
  7656.         }
  7657.     }
  7658.  
  7659.     for (i=0; i<a.length; ++i) {
  7660.         if ( aa[i] == 1 ) {
  7661.             for (j=max(0,i-context); j < min(a.length, i+context); ++j) {
  7662.                 if ( !aa[j] ) { aa[j] = 1; bb[ a[j].row ] = 0.5; }
  7663.             }
  7664.         }
  7665.     }
  7666.  
  7667.     for (i=0; i<bb.length; ++i) {
  7668.         if (bb[i] > 0) { // it's a row we need
  7669.             if (b[i].paired) { bbb.push(b[i].text); } // joined; partner should be in aa
  7670.             else {
  7671.                 bbb.push(b[i]);
  7672.             }
  7673.         }
  7674.     }
  7675.     for (i=0; i<aa.length; ++i) {
  7676.         if (aa[i] > 0) { // it's a row we need
  7677.             if (a[i].paired) { aaa.push(a[i].text); } // joined; partner should be in aa
  7678.             else {
  7679.                 aaa.push(a[i]);
  7680.             }
  7681.         }
  7682.     }
  7683.  
  7684.     return { a: aaa, b: bbb};
  7685. }
  7686.  
  7687. function stripOuterCommonLines(a,b,context) {
  7688.     var i=0;
  7689.     while (i<a.length && i < b.length && a[i]==b[i]) { ++i; }
  7690.     var j=a.length-1; var k=b.length-1;
  7691.     while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; }
  7692.  
  7693.     return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)),
  7694.                 b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) };
  7695. }
  7696.  
  7697. function insertDiff(navpop) {
  7698.     // for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff
  7699.     // FIXME: sometimes this gives misleading diffs as distant chunks are squashed together
  7700.     var oldlines=navpop.diffData.Old.data.split('\n');
  7701.     var newlines=navpop.diffData.New.data.split('\n');
  7702.     var inner=stripOuterCommonLines(oldlines,newlines,getValueOf('popupDiffContextLines'));
  7703.     oldlines=inner.a; newlines=inner.b;
  7704.     var truncated=false;
  7705.     getValueOf('popupDiffMaxLines');
  7706.     if (oldlines.length > pg.option.popupDiffMaxLines || newlines.length > pg.option.popupDiffMaxLines) {
  7707.         // truncate
  7708.         truncated=true;
  7709.         inner=stripOuterCommonLines(oldlines.slice(0,pg.option.popupDiffMaxLines),
  7710.                         newlines.slice(0,pg.option.popupDiffMaxLines),
  7711.                         pg.option.popupDiffContextLines);
  7712.         oldlines=inner.a; newlines=inner.b;
  7713.     }
  7714.  
  7715.     var lineDiff=diff(oldlines, newlines);
  7716.     var lines2=rmBoringLines(lineDiff.o, lineDiff.n);
  7717.     var oldlines2=lines2.a; var newlines2=lines2.b;
  7718.  
  7719.     var simpleSplit = !String.prototype.parenSplit.isNative;
  7720.     var html='<hr>';
  7721.     if (getValueOf('popupDiffDates')) {
  7722.         html += diffDatesTable(navpop.diffData.Old, navpop.diffData.New);
  7723.         html += '<hr>';
  7724.     }
  7725.     html += shortenDiffString(
  7726.         diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit),
  7727.         getValueOf('popupDiffContextCharacters') ).join('<hr>');
  7728.     setPopupTipsAndHTML(html.split('\n').join('<br>') +
  7729.              (truncated ? '<hr><b>'+popupString('Diff truncated for performance reasons')+'</b>' : '') ,
  7730.                 'popupPreview', navpop.idNumber);
  7731. }
  7732.  
  7733. function diffDatesTable( oldDl, newDl ) {
  7734.     var html='<table class="popup_diff_dates">';
  7735.     html += diffDatesTableRow( newDl, tprintf('New revision'));
  7736.     html += diffDatesTableRow( oldDl, tprintf('Old revision'));
  7737.     html += '</table>';
  7738.     return html;
  7739. }
  7740. function diffDatesTableRow( dl, label ) {
  7741.     var txt='';
  7742.     if (!dl) {
  7743.         txt=popupString('Something went wrong :-(');
  7744.     } else if (!dl.lastModified) {
  7745.         txt= (/^\s*$/.test(dl.data)) ?
  7746.             popupString('Empty revision, maybe non-existent') : popupString('Unknown date');
  7747.     } else {
  7748.         var datePrint=getValueOf('popupDiffDatePrinter');
  7749.         if (typeof dl.lastModified[datePrint] == 'function') {
  7750.             if (getValueOf('popupAdjustDiffDates')) {
  7751.                 var off;
  7752.                 if (off=Cookie.read('popTz')) {
  7753.                     var d2=adjustDate(dl.lastModified, off);
  7754.                     txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true);
  7755.                 }
  7756.             } else {
  7757.                 txt = dl.lastModified[datePrint]();
  7758.             }
  7759.         } else {
  7760.             txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]);
  7761.         }
  7762.     }
  7763.     var revlink = generalLink({url: dl.url.replace(/&.*?(oldid=[0-9]+(?:&direction=[^&]*)?).*/, '&$1'),
  7764.                    text: label, title: label});
  7765.     return simplePrintf('<tr><td>%s</td><td>%s</td></tr>', [ revlink, txt ]);
  7766. }
  7767. //</NOLITE>
  7768. // ENDFILE: diffpreview.js
  7769. // STARTFILE: links.js
  7770. //<NOLITE>
  7771. /////////////////////
  7772. // LINK GENERATION //
  7773. /////////////////////
  7774.  
  7775. // titledDiffLink --> titledWikiLink --> generalLink
  7776. // wikiLink       --> titledWikiLink --> generalLink
  7777. // editCounterLink --> generalLink
  7778.  
  7779. function titledDiffLink(l) { // article, text, title, from, to) {
  7780.     return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from,
  7781.                 newWin: l.newWin,
  7782.                 noPopup: l.noPopup,
  7783.                 text: l.text, title: l.title,
  7784.                 /* hack: no oldid here */
  7785.                 actionName: 'diff'});
  7786. }
  7787.  
  7788.  
  7789. function wikiLink(l) {
  7790.     //{article:article, action:action, text:text, oldid, newid}) {
  7791.     if (! (typeof l.article == typeof {}
  7792.            && typeof l.action == typeof '' && typeof l.text==typeof '')) return null;
  7793.     if (typeof l.oldid == 'undefined') { l.oldid=null; }
  7794.     var savedOldid = l.oldid;
  7795.     if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { l.oldid=null; }
  7796.     var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc
  7797.     var oldidData=[l.oldid, safeDecodeURI(l.article)];
  7798.     var revisionString = tprintf('revision %s of %s', oldidData);
  7799.     log('revisionString='+revisionString);
  7800.     switch (l.action) {
  7801.     case 'edit§ion=new': hint = popupString('newSectionHint');  break;
  7802.     case 'edit&undo=':
  7803.         if (l.diff && l.diff != 'prev' && savedOldid ) {
  7804.           l.action += l.diff + '&undoafter=' + savedOldid;
  7805.         } else if (savedOldid) {
  7806.           l.action += savedOldid;
  7807.         }
  7808.         hint = popupString('undoHint');
  7809.         break;
  7810.     case 'raw&ctype=text/css': hint=popupString('rawHint'); break;
  7811.     case 'revert':
  7812.         if (!window.wgEnableAPI || !wgEnableAPI) {
  7813.             alert( '');
  7814.             break;
  7815.         }
  7816.         var p=parseParams(pg.current.link.href);
  7817.         l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autosummary=' + revertSummary(l.oldid, p.diff);
  7818.         if (p.diff=='prev') {
  7819.             l.action += '&direction=prev';
  7820.             revisionString = tprintf('the revision prior to revision %s of %s', oldidData);
  7821.         }
  7822.         if (getValueOf('popupRevertSummaryPrompt')) { l.action += '&autosummaryprompt=true'; }
  7823.         if (getValueOf('popupMinorReverts')) { l.action += '&autominor=true'; }
  7824.         log('revisionString is now '+revisionString);
  7825.         break;
  7826.     case 'nullEdit':
  7827.         l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autosummary=null';
  7828.         break;
  7829.     case 'historyfeed':
  7830.         l.action='history&feed=rss';
  7831.         break;
  7832.     case 'markpatrolled':
  7833.         l.action='markpatrolled&rcid='+l.rcid;
  7834.     }
  7835.  
  7836.     if (hint) {
  7837.         if (l.oldid) {
  7838.             hint = simplePrintf(hint, [revisionString]);
  7839.         }
  7840.         else {
  7841.             hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
  7842.         }
  7843.     }
  7844.     else {
  7845.         hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : '';
  7846.     }
  7847.  
  7848.     return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin,
  7849.                 title: hint, oldid: l.oldid, noPopup: l.noPopup});
  7850. }
  7851.  
  7852. function revertSummary(oldid, diff) {
  7853.     var ret='';
  7854.     if (diff == 'prev') {
  7855.         ret=getValueOf('popupQueriedRevertToPreviousSummary');
  7856.     } else { ret = getValueOf('popupQueriedRevertSummary'); }
  7857.     return ret + '&autorv=' + oldid;
  7858. }
  7859.  
  7860. function titledWikiLink(l) {
  7861.     // possible properties of argument:
  7862.     // article, action, text, title, oldid, actionName, className, noPopup
  7863.     // oldid = null is fine here
  7864.  
  7865.     // article and action are mandatory args
  7866.  
  7867.     if (typeof l.article == 'undefined' || typeof l.action=='undefined') {
  7868.         errlog('got undefined article or action in titledWikiLink');
  7869.         return null;
  7870.     }
  7871.  
  7872.     var base = pg.wiki.titlebase +  l.article.urlString();
  7873.     var url=base;
  7874.  
  7875.     if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; }
  7876.  
  7877.     // no need to add &action=view, and this confuses anchors
  7878.     if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; }
  7879.  
  7880.     if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; }
  7881.  
  7882.     var cssClass=pg.misc.defaultNavlinkClassname;
  7883.     if (typeof l.className!='undefined' && l.className) { cssClass=l.className; }
  7884.  
  7885.     return generalNavLink({url: url, newWin: l.newWin,
  7886.                 title: (typeof l.title != 'undefined') ? l.title : null,
  7887.                 text: (typeof l.text!='undefined')?l.text:null,
  7888.                 className: cssClass, noPopup:l.noPopup});
  7889. }
  7890.  
  7891. function getLastContrib(wikipage, newWin) {
  7892.     getHistoryInfo(wikipage, function(x){processLastContribInfo(x,{page: wikipage, newWin: newWin})});
  7893. }
  7894. function processLastContribInfo(info, stuff) {
  7895.     if(!info.edits || !info.edits.length) { alert('Popups: an odd thing happened. Please retry.'); return; }
  7896.     if(!info.firstNewEditor) {
  7897.         alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length]));
  7898.         return;
  7899.     }
  7900.     var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+info.firstNewEditor.oldid;
  7901.     displayUrl(newUrl, stuff.newWin);
  7902. }
  7903. function getDiffSinceMyEdit(wikipage, newWin) {
  7904.     getHistoryInfo(wikipage, function(x){processDiffSinceMyEdit(x,{page: wikipage, newWin: newWin})});
  7905. }
  7906. function processDiffSinceMyEdit(info, stuff) {
  7907.     if(!info.edits || !info.edits.length) { alert('Popups: something fishy happened. Please try again.'); return; }
  7908.     var friendlyName=stuff.page.split('_').join(' ');
  7909.     if(!info.myLastEdit) {
  7910.         alert(tprintf('Couldn\'t find an edit by %s\nin the last %s edits to\n%s',
  7911.                   [info.userName, getValueOf('popupHistoryLimit'), friendlyName]));
  7912.         return;
  7913.     }
  7914.     if(info.myLastEdit.index==0) {
  7915.         alert(tprintf("%s seems to be the last editor to the page %s", [info.userName, friendlyName]));
  7916.         return;
  7917.     }
  7918.     var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+ info.myLastEdit.oldid;
  7919.     displayUrl(newUrl, stuff.newWin);
  7920. }
  7921. function displayUrl(url, newWin){
  7922.     if(newWin) { window.open(url); }
  7923.     else { document.location=url; }
  7924. }
  7925.  
  7926. function purgePopups() {
  7927.     processAllPopups(true);
  7928.     setupCache(); // deletes all cached items (not browser cached, though...)
  7929.     pg.option={};
  7930.     abortAllDownloads();
  7931. }
  7932.  
  7933. function processAllPopups(nullify, banish) {
  7934.     for (var i=0; i<pg.current.links.length; ++i) {
  7935.         if (!pg.current.links[i].navpopup) { continue; }
  7936.         (nullify || banish) && pg.current.links[i].navpopup.banish();
  7937.         pg.current.links[i].simpleNoMore=false;
  7938.         nullify && (pg.current.links[i].navpopup=null);
  7939.     }
  7940. }
  7941.  
  7942. function disablePopups(){
  7943.     processAllPopups(false, true);
  7944.     setupTooltips(null, true);
  7945. }
  7946.  
  7947. function togglePreviews() {
  7948.     processAllPopups(true, true);
  7949.     pg.option.simplePopups=!pg.option.simplePopups;
  7950.     abortAllDownloads();
  7951. }
  7952.  
  7953. function magicHistoryLink(l) {
  7954.     // FIXME use onclick change href trick to sort this out instead of window.open
  7955.  
  7956.     var jsUrl='', title='';
  7957.     switch(l.id) {
  7958.     case 'lastContrib':
  7959.         jsUrl=simplePrintf('javascript:getLastContrib(\'%s\',%s)',
  7960.             [l.article.toString(true).split("'").join("\\'"), l.newWin]);
  7961.         title=popupString('lastContribHint');
  7962.         break;
  7963.     case 'sinceMe':
  7964.         jsUrl=simplePrintf('javascript:getDiffSinceMyEdit(\'%s\',%s)',
  7965.             [l.article.toString(true).split("'").join("\\'"), l.newWin]);
  7966.         title=popupString('sinceMeHint');
  7967.         break;
  7968.     }
  7969.  
  7970.     return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think
  7971.                 title: title, text: l.text, noPopup: l.noPopup});
  7972. }
  7973.  
  7974. function popupMenuLink(l) {
  7975.     var jsUrl=simplePrintf('javascript:%s()', [l.id]);
  7976.     var title=popupString(simplePrintf('%sHint', [l.id]));
  7977.     return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup});
  7978. }
  7979.  
  7980. function specialLink(l) {
  7981.     // properties: article, specialpage, text, sep
  7982.     if (typeof l.specialpage=='undefined'||!l.specialpage) return null;
  7983.     var base = pg.wiki.titlebase +  pg.ns.special+':'+l.specialpage;
  7984.     if (typeof l.sep == 'undefined' || l.sep===null) l.sep='&target=';
  7985.     var article=l.article.urlString({keepSpaces: l.specialpage=='Search'});
  7986.     var hint=popupString(l.specialpage+'Hint');
  7987.     switch (l.specialpage) {
  7988.     case 'Log':
  7989.         switch (l.sep) {
  7990.         case '&user=': hint=popupString('userLogHint'); break;
  7991.         case '&type=block&page=': hint=popupString('blockLogHint'); break;
  7992.         case '&page=': hint=popupString('pageLogHint'); break;
  7993.         case '&type=protect&page=': hint=popupString('protectLogHint'); break;
  7994.         case '&type=delete&page=': hint=popupString('deleteLogHint'); break;
  7995.         default: log('Unknown log type, sep=' + l.sep); hint='Missing hint (FIXME)';
  7996.         }
  7997.         break;
  7998.     case 'Prefixindex': article += '/'; break;
  7999.     }
  8000.     if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
  8001.     else hint = safeDecodeURI(l.specialpage+':'+l.article) ;
  8002.  
  8003.     var url = base + l.sep + article;
  8004.     return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup});
  8005. }
  8006.  
  8007. function generalLink(l) {
  8008.     // l.url, l.text, l.title, l.newWin, l.className, l.noPopup
  8009.     if (typeof l.url=='undefined') return null;
  8010.  
  8011.     // only quotation marks in the url can screw us up now... I think
  8012.     var url=l.url.split('"').join('%22');
  8013.  
  8014.     var ret='<a href="' + url + '"';
  8015.     if (typeof l.title!='undefined' && l.title) { ret += ' title="' + l.title + '"'; }
  8016.     if (l.noPopup) { ret += ' noPopup=1'; }
  8017.     var newWin;
  8018.     if (typeof l.newWin=='undefined' || l.newWin===null) { newWin=getValueOf('popupNewWindows'); }
  8019.     else { newWin=l.newWin; }
  8020.     if (newWin) { ret += ' target="_blank"'; }
  8021.     if (typeof l.className!='undefined'&&l.className) { ret+=' class="'+l.className+'"'; }
  8022.     ret += '>';
  8023.     if (WikiLook_Overlay._currentWord.replace("_"," ","ig").indexOf(l.text)!=-1) {
  8024.         WikiLook_Overlay._currentWord.replace(" ","_","ig");
  8025.         if (typeof l.text==typeof '') { ret+= '<span class="popup_mainlink">'+ l.text + '</span>';}
  8026.         }
  8027.     else {
  8028.         if (typeof l.text==typeof '') { ret+= l.text;}
  8029.         }
  8030.     ret +='</a>';
  8031.     return ret;
  8032. }
  8033.  
  8034. function appendParamsToLink(linkstr, params) {
  8035.     var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i'));
  8036.     if (sp.length<2) return null;
  8037.     var ret=sp.shift() + sp.shift();
  8038.     ret += '&' + params + '"';
  8039.     ret += sp.join('');
  8040.     return ret;
  8041. }
  8042.  
  8043. function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional) {
  8044.     if (x.newTarget) {
  8045.         log ('changeLinkTargetLink: newTarget=' + x.newTarget);
  8046.     }
  8047.     // optional: oldTarget (in wikitext)
  8048.     // if x.newTarget omitted or null, remove the link
  8049.  
  8050.     //x.text=encodeURI(x.text);  // this buggers things up on zh.wikipedia.org and doesn't seem necessary
  8051.     x.clickButton=encodeURI(x.clickButton);
  8052.  
  8053.     // FIXME: first character of page title as well as namespace should be case insensitive
  8054.     // eg [[category:foo]] and [[Category:Foo]] are equivalent
  8055.     // this'll break if charAt(0) is nasty
  8056.     var cA=literalizeRegex(x.oldTarget);
  8057.     var chs=cA.charAt(0).toUpperCase();
  8058.     chs='['+chs + chs.toLowerCase()+']';
  8059.     var currentArticleRegexBit=encodeURIComponent(chs+cA.substring(1));
  8060.     currentArticleRegexBit=currentArticleRegexBit
  8061.         .split(RegExp('[_ ]+', 'g')).join('[_ ]+')
  8062.         .split('\\(').join('(?:%2528|\\()')
  8063.         .split('\\)').join('(?:%2529|\\))');
  8064.     // leading and trailing space should be ignored, and anchor bits optional:
  8065.     currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*';
  8066.     // e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s*
  8067.  
  8068.     // autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g
  8069.  
  8070.     var title=x.title || wgPageName.split('_').join(' ');
  8071.     var lk=titledWikiLink({article: new Title(title), newWin:x.newWin,
  8072.                         action:  'edit',
  8073.                         text:    x.text,
  8074.                         title:   x.hint,
  8075.                         className: 'popup_change_title_link'
  8076.                         });
  8077.     var cmd='';
  8078.     if (x.newTarget) {
  8079.         // escape '&' and other nasties
  8080.         var t=encodeURIComponent(x.newTarget);
  8081.         var s=encodeURIComponent(literalizeRegex(x.newTarget));
  8082.         cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~[['+t+'|$1]]~g;';
  8083.         cmd += 's~\\[\\['+currentArticleRegexBit+'[|]~[['+t+'|~g;';
  8084.         cmd += 's~\\[\\['+s + '\\|' + s + '\\]\\]~[[' + t + ']]~g';
  8085.     } else {
  8086.         cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;';
  8087.         cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g';
  8088.     }
  8089.     cmd += '&autoclick='+x.clickButton + '&actoken=' + autoClickToken();
  8090.     cmd += ( x.minor == null ) ? '' : '&autominor='+x.minor;
  8091.     cmd += ( x.watch == null ) ? '' : '&autowatch='+x.watch;
  8092.     cmd += '&autosummary='+encodeURIComponent(x.summary);
  8093.     return appendParamsToLink(lk, 'autoedit='+cmd);
  8094. }
  8095.  
  8096.  
  8097. function redirLink(redirMatch, article) {
  8098.     // NB redirMatch is in wikiText
  8099.     var ret='';
  8100.  
  8101.     if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) {
  8102.         ret += '<hr>';
  8103.         if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) {
  8104.             log('redirLink: newTarget=' + redirMatch);
  8105.             ret += addPopupShortcut(
  8106.                 changeLinkTargetLink(
  8107.                 {newTarget: redirMatch, text: popupString('Redirects'),
  8108.                     hint: popupString('Fix this redirect'),
  8109.                         summary: simplePrintf(getValueOf('popupFixRedirsSummary'),
  8110.                                       [article.toString(), redirMatch ]),
  8111.                         oldTarget: article.toString(),
  8112.                         clickButton: getValueOf('popupRedirAutoClick'), minor: true,
  8113.                         watch: getValueOf('popupWatchRedirredPages')})
  8114.                 , 'R');
  8115.             ret += popupString(' to ');
  8116.         }
  8117.         else ret += popupString('Redirects') + popupString(' to ');
  8118.         return ret;
  8119.     }
  8120.  
  8121.     else return '<br> ' + popupString('Redirects') + popupString(' to ') +
  8122.              titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view',  /* FIXME: newWin */
  8123.                               text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')});
  8124. }
  8125.  
  8126. function arinLink(l) {
  8127.     if (!saneLinkCheck(l)) { return null; }
  8128.     if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null;
  8129.  
  8130.     var uN=l.article.userName();
  8131.  
  8132.     return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), newWin:l.newWin,
  8133.                 title: tprintf('Look up %s in ARIN whois database', [uN]),
  8134.                 text: l.text, noPopup:1});
  8135. }
  8136.  
  8137. function toolDbName(cookieStyle) {
  8138.     var ret=null;
  8139.     var theWiki=pg.wiki.hostname.split('.')[1];
  8140.     if (pg.wiki.hostname==pg.wiki.commons) {
  8141.         ret = 'commonswiki';
  8142.     } else {
  8143.         switch(theWiki) {
  8144.         case 'wikipedia':
  8145.         case 'wikimedia':
  8146.             ret = pg.wiki.lang + 'wiki';
  8147.             break;
  8148.         default:
  8149.             ret = pg.wiki.lang + theWiki;
  8150.             break;
  8151.         }
  8152.     }
  8153.     if (!cookieStyle) { ret+= '_p'; }
  8154.     return ret;
  8155. }
  8156.  
  8157. function saneLinkCheck(l) {
  8158.     if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; }
  8159.     return true;
  8160. }
  8161. function editCounterLink(l) {
  8162.     if(!saneLinkCheck(l)) return null;
  8163.     if (! pg.wiki.wikimedia) return null;
  8164.     var uN=l.article.userName();
  8165.     var tool=getValueOf('popupEditCounterTool');
  8166.     var url;
  8167.     var soxredToolUrl='http://toolserver.org/~soxred93/count/index.php?name=$1&lang=$2&wiki=$3';
  8168.     var kateToolUrl='http://toolserver.org/~$3/cgi-bin/Tool1/wannabe_kate?username=$1&site=en.wikipedia.org&$2';
  8169.  
  8170.     switch(tool) {
  8171.     case 'custom':
  8172.         url=simplePrintf(getValueOf('popupEditCounterUrl'), [ encodeURIComponent(uN), toolDbName() ]);
  8173.         break;
  8174.     case 'kate':
  8175.     case 'interiot':
  8176.         url=simplePrintf(kateToolUrl, [ encodeURIComponent(uN), toolDbName(), tool ]);
  8177.         break;
  8178.     default:
  8179.         var theWiki=pg.wiki.hostname.split('.');
  8180.         url=simplePrintf(soxredToolUrl, [ encodeURIComponent(uN), theWiki[0], theWiki[1] ]);
  8181.     }
  8182.     return generalNavLink({url:url, title: tprintf('editCounterLinkHint', [uN]),
  8183.                 newWin:l.newWin, text: l.text, noPopup:1});
  8184. }
  8185.  
  8186.  
  8187. function globalSearchLink(l) {
  8188.     if(!saneLinkCheck(l)) return null;
  8189.  
  8190.     var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search=';
  8191.     var article=l.article.urlString({keepSpaces:true});
  8192.  
  8193.     return generalNavLink({url:base + article, newWin:l.newWin,
  8194.                 title: tprintf('globalSearchHint', [article]),
  8195.                 text: l.text, noPopup:1});
  8196. }
  8197.  
  8198. function googleLink(l) {
  8199.     if(!saneLinkCheck(l)) return null;
  8200.  
  8201.     var base='http://www.google.com/search?q=';
  8202.     var article=l.article.urlString({keepSpaces:true});
  8203.  
  8204.     return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin,
  8205.                 title: tprintf('googleSearchHint', [article]),
  8206.                 text: l.text, noPopup:1});
  8207. }
  8208.  
  8209. function editorListLink(l) {
  8210.     if(!saneLinkCheck(l)) return null;
  8211.     var article= l.article.articleFromTalkPage() || l.article;
  8212.     var base='http://toolserver.org/~tim/cgi-bin/contribution-counter?page=';
  8213.     return generalNavLink({url:base+article.urlString(),
  8214.                 title: tprintf('editorListHint', [article]),
  8215.                 newWin:l.newWin, text: l.text, noPopup:1});
  8216. }
  8217.  
  8218. function generalNavLink(l) {
  8219.     l.className = (l.className==null) ? 'popupNavLink' : l.className;
  8220.     return generalLink(l);
  8221. }
  8222.  
  8223. //////////////////////////////////////////////////
  8224. // magic history links
  8225. //
  8226.  
  8227. function getHistoryInfo(wikipage, whatNext) {
  8228.     log('getHistoryInfo');
  8229.     getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory);
  8230. }
  8231.  
  8232. // FIXME eliminate pg.idNumber ... how? :-(
  8233.  
  8234. function getHistory(wikipage, onComplete) {
  8235.     log('getHistory');
  8236.     if( !window.wgEnableAPI || !wgEnableAPI ) {
  8237.         alert( '');
  8238.         return false;
  8239.     }
  8240.     var url = pg.wiki.wikibase + '/api.php?format=json&action=query&prop=revisions&titles=' +
  8241.             new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit');
  8242.     log('getHistory: url='+url);
  8243.     return startDownload(url, pg.idNumber+'history', onComplete);
  8244. }
  8245.  
  8246. function processHistory(download) {
  8247.     var jsobj = getJsObj(download.data);
  8248.     try {
  8249.         window.x=jsobj;
  8250.         var p=jsobj['query']['pages']
  8251.         for (var pageid in p) {
  8252.             var revisions=p[pageid]['revisions'];
  8253.             // we only get the first one
  8254.             break;
  8255.         }
  8256.     } catch (someError) {
  8257.         log('Something went wrong with JSON business');
  8258.         return finishProcessHistory([]);
  8259.     }
  8260.     var edits=[];
  8261.     for (var i=0; i<revisions.length; ++i) {
  8262.         edits.push({ oldid: revisions[i]['revid'], editor: revisions[i]['user'] });
  8263.     }
  8264.     log('processed ' + edits.length + ' edits');
  8265.     return finishProcessHistory(edits, wgUserName);
  8266. }
  8267.  
  8268.  
  8269. function finishProcessHistory(edits, userName) {
  8270.     var histInfo={};
  8271.  
  8272.     histInfo.edits=edits;
  8273.     histInfo.userName=userName;
  8274.  
  8275.     for (var i=0; i<edits.length; ++i) {
  8276.         if (typeof histInfo.myLastEdit == 'undefined' && userName && edits[i].editor==userName) {
  8277.             histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)};
  8278.         }
  8279.         if (typeof histInfo.firstNewEditor == 'undefined' && edits[i].editor != edits[0].editor) {
  8280.             histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)};
  8281.         }
  8282.     }
  8283.     //pg.misc.historyInfo=histInfo;
  8284.     return histInfo;
  8285. }
  8286. //</NOLITE>
  8287. // ENDFILE: links.js
  8288. // STARTFILE: options.js
  8289. //////////////////////////////////////////////////
  8290. // options
  8291.  
  8292. // check for cookies and existing value, else use default
  8293. function defaultize(x) {
  8294.     var val=null;
  8295.     if (x!='popupCookies') {
  8296.         defaultize('popupCookies');
  8297.         if (pg.option.popupCookies && (val=Cookie.read(x))) {
  8298.             pg.option[x]=val;
  8299.             return;
  8300.         }
  8301.     }
  8302.     if (pg.option[x]===null || typeof pg.option[x]=='undefined') {
  8303.         if (typeof window[x] != 'undefined' ) pg.option[x]=window[x];
  8304.         else pg.option[x]=pg.optionDefault[x];
  8305.     }
  8306. }
  8307.  
  8308. function newOption(x, def) {
  8309.     pg.optionDefault[x]=def;
  8310. }
  8311.  
  8312. function setDefault(x, def) {
  8313.     return newOption(x, def);
  8314. }
  8315.  
  8316. function getValueOf(varName) {
  8317.     defaultize(varName);
  8318.     return pg.option[varName];
  8319. }
  8320.  
  8321. function useDefaultOptions() { // for testing
  8322.     for (var p in pg.optionDefault) {
  8323.         pg.option[p]=pg.optionDefault[p];
  8324.         if (typeof window[p]!='undefined') { delete window[p]; }
  8325.     }
  8326. }
  8327.  
  8328. function setOptions() {
  8329.     // user-settable parameters and defaults
  8330.  
  8331.     // Basic options
  8332.     newOption('popupDelay',               0.0);
  8333.     newOption('popupHideDelay',           0.5);
  8334.     newOption('simplePopups',             false);
  8335.     newOption('popupStructure',           'shortmenus');   // see later - default for popupStructure is 'original' if simplePopups is true
  8336.     newOption('popupActionsMenu',         true);
  8337.     newOption('popupSetupMenu',           true);
  8338.     newOption('popupAdminLinks',          false);
  8339.     newOption('popupShortcutKeys',        false);
  8340.     newOption('popupHistoricalLinks',     true);
  8341.     newOption('popupOnlyArticleLinks',    true);
  8342.     newOption('removeTitles',             true);
  8343.     newOption('popupMaxWidth',            350);
  8344.     newOption('popupInitialWidth',        false); // integer or false
  8345.     newOption('popupSimplifyMainLink',    true);
  8346.     newOption('popupAppendRedirNavLinks', true);
  8347.     newOption('popupTocLinks',            false);
  8348.     newOption('popupSubpopups',           true);
  8349.     newOption('popupDragHandle',          false /* 'popupTopLinks'*/);
  8350.     newOption('popupLazyPreviews',        true);
  8351.     newOption('popupLazyDownloads',       true);
  8352.     newOption('popupAllDabsStubs',        false);
  8353.     newOption('popupDebugging',           false);
  8354.     newOption('popupAdjustDiffDates',     true);
  8355.     newOption('popupActiveNavlinks',      true);
  8356.     newOption('popupModifier',            false); // ctrl, shift, alt or meta
  8357.     newOption('popupModifierAction',      'enable'); // or 'disable'
  8358.  
  8359. //<NOLITE>
  8360.     // images
  8361.     newOption('popupImages',                 true);
  8362.     newOption('imagePopupsForImages',        true);
  8363.     newOption('popupNeverGetThumbs',         false);
  8364.     newOption('popupImagesFromThisWikiOnly', false);
  8365.     newOption('popupMinImageWidth',          50);
  8366.     newOption('popupLoadImagesSequentially', false);
  8367.     //newOption('popupImagesToggleSize',       true);
  8368.     newOption('popupThumbAction',            'imagepage'); //'sizetoggle');
  8369.     newOption('popupImageSize',              60);
  8370.  
  8371.     // redirs, dabs, reversion
  8372.     newOption('popupFixRedirs',             false);
  8373.     newOption('popupRedirAutoClick',        'wpDiff');
  8374.     newOption('popupFixDabs',               false);
  8375.     newOption('popupRevertSummaryPrompt',   false);
  8376.     newOption('popupMinorReverts',          false);
  8377.     newOption('popupRedlinkRemoval',        false);
  8378.     newOption('popupWatchDisambiggedPages', null);
  8379.     newOption('popupWatchRedirredPages',    null);
  8380.     newOption('popupDabWiktionary',         'last');
  8381.  
  8382.     // navlinks
  8383.     newOption('popupNavLinks',          true);
  8384.     newOption('popupNavLinkSeparator',  ' ⋅ ');
  8385.     newOption('popupLastEditLink',      true);
  8386.     newOption('popupEditCounterTool',   'soxred');
  8387.     newOption('popupEditCounterUrl',    '');
  8388.     newOption('popupExtraUserMenu',     '');
  8389. //</NOLITE>
  8390.  
  8391.     // previews etc
  8392.     newOption('popupPreviews',             true);
  8393.     newOption('popupSummaryData',          true);
  8394.     newOption('popupMaxPreviewSentences',  5);
  8395.     newOption('popupMaxPreviewCharacters', 600);
  8396.     newOption('popupLastModified',         true);
  8397.     newOption('popupPreviewKillTemplates', true);
  8398.     newOption('popupPreviewRawTemplates',  true);
  8399.     newOption('popupPreviewFirstParOnly',  true);
  8400.     newOption('popupPreviewCutHeadings',   true);
  8401.     newOption('popupPreviewButton',        false);
  8402.     newOption('popupPreviewButtonEvent',   'click');
  8403.  
  8404. //<NOLITE>
  8405.     // diffs
  8406.     newOption('popupPreviewDiffs',          true);
  8407.     newOption('popupDiffMaxLines',          100);
  8408.     newOption('popupDiffContextLines',      2);
  8409.     newOption('popupDiffContextCharacters', 40);
  8410.     newOption('popupDiffDates',             true);
  8411.     newOption('popupDiffDatePrinter',       'toLocaleString');
  8412.  
  8413.     // edit summaries. God, these are ugly.
  8414.     newOption('popupFixDabsSummary',           popupString('defaultpopupFixDabsSummary') );
  8415.     newOption('popupExtendedRevertSummary',    popupString('defaultpopupExtendedRevertSummary') );
  8416.     newOption('popupTimeOffset',               null);
  8417.     newOption('popupRevertSummary',            popupString('defaultpopupRevertSummary') );
  8418.     newOption('popupRevertToPreviousSummary',  popupString('defaultpopupRevertToPreviousSummary') );
  8419.     newOption('popupQueriedRevertSummary',            popupString('defaultpopupQueriedRevertSummary') );
  8420.     newOption('popupQueriedRevertToPreviousSummary',  popupString('defaultpopupQueriedRevertToPreviousSummary') );
  8421.     newOption('popupFixRedirsSummary',         popupString('defaultpopupFixRedirsSummary') );
  8422.     newOption('popupRedlinkSummary',           popupString('defaultpopupRedlinkSummary') );
  8423.     newOption('popupRmDabLinkSummary',         popupString('defaultpopupRmDabLinkSummary') );
  8424. //</NOLITE>
  8425.     // misc
  8426.     newOption('popupCookies',             false);
  8427.     newOption('popupHistoryLimit',        50);
  8428. //<NOLITE>
  8429.     newOption('popupFilters',             [popupFilterStubDetect,     popupFilterDisambigDetect,
  8430.                            popupFilterPageSize,       popupFilterCountLinks,
  8431.                            popupFilterCountImages,    popupFilterCountCategories,
  8432.                            popupFilterLastModified]);
  8433.     newOption('extraPopupFilters',        []);
  8434.     newOption('popupOnEditSelection', 'cursor');
  8435.     newOption('popupPreviewHistory',      true);
  8436.     newOption('popupImageLinks',          true);
  8437.     newOption('popupCategoryMembers',     true);
  8438.     newOption('popupUserInfo',            true);
  8439.     newOption('popupHistoryPreviewLimit', 25);
  8440.     newOption('popupContribsPreviewLimit',25);
  8441. //</NOLITE>
  8442.  
  8443.     // new windows
  8444.     newOption('popupNewWindows',     false);
  8445.     newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true});
  8446.  
  8447.     // regexps
  8448.     newOption('popupDabRegexp', '([{][{]\\s*disambig|disambig\\s*[}][}]|disamb\\s*[}][}]|dab\\s*[}][}])|[{][{]\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|shipindex)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page');
  8449.     newOption('popupStubRegexp', '(sect)?stub[}][}]|This .*-related article is a .*stub');
  8450.     newOption('popupImageVarsRegexp', 'image|image_(?:file|skyline|name|flag|seal)|cover|badge|logo');
  8451. }
  8452. // ENDFILE: options.js
  8453. // STARTFILE: strings.js
  8454. //<NOLITE>
  8455. //////////////////////////////////////////////////
  8456. // Translatable strings
  8457. //////////////////////////////////////////////////
  8458. //
  8459. // See instructions at
  8460. // http://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation
  8461.  
  8462. pg.string = {
  8463.     /////////////////////////////////////
  8464.     // summary data, searching etc.
  8465.     /////////////////////////////////////
  8466.     'article': 'article',
  8467.     'category': 'category',
  8468.     'categories': 'categories',
  8469.     'image': 'image',
  8470.     'images': 'images',
  8471.     'stub': 'stub',
  8472.     'section stub': 'section stub',
  8473.     'Empty page': 'Empty page',
  8474.     'kB': 'kB',
  8475.     'bytes': 'bytes',
  8476.     'day': 'day',
  8477.     'days': 'days',
  8478.     'hour': 'hour',
  8479.     'hours': 'hours',
  8480.     'minute': 'minute',
  8481.     'minutes': 'minutes',
  8482.     'second': 'second',
  8483.     'seconds': 'seconds',
  8484.     'week': 'week',
  8485.     'weeks': 'weeks',
  8486.     'search': 'search',
  8487.     'SearchHint': 'Find English Wikipedia articles containing %s',
  8488.     'web': 'web',
  8489.     'global': 'global',
  8490.     'globalSearchHint': 'Search across Wikipedias in different languages for %s',
  8491.     'googleSearchHint': 'Google for %s',
  8492.     /////////////////////////////////////
  8493.     // article-related actions and info
  8494.     // (some actions also apply to user pages)
  8495.     /////////////////////////////////////
  8496.     'actions': 'actions',         ///// view articles and view talk
  8497.     'popupsMenu': 'popups',
  8498.     'togglePreviewsHint': 'Toggle preview generation in popups on this page',
  8499.     'enable previews': 'enable previews',
  8500.     'disable preview': 'disable previews',
  8501.     'toggle previews': 'toggle previews',
  8502.     'show preview': 'show preview',
  8503.     'reset': 'reset',
  8504.     'more...': 'more...',
  8505.     'disable': 'disable popups',
  8506.     'disablePopupsHint': 'Disable popups on this page. Reload page to re-enable.',
  8507.     'historyfeedHint': 'RSS feed of recent changes to this page',
  8508.     'purgePopupsHint': 'Reset popups, clearing all cached popup data.',
  8509.     'PopupsHint': 'Reset popups, clearing all cached popup data.',
  8510.     'spacebar': 'space',
  8511.     'view': 'view',
  8512.     'view article': 'view article',
  8513.     'viewHint': 'Go to %s',
  8514.     'talk': 'talk',
  8515.     'talk page': 'talk page',
  8516.     'this revision': 'this revision',
  8517.     'revision %s of %s': 'revision %s of %s',
  8518.     'Revision %s of %s': 'Revision %s of %s',
  8519.     'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s',
  8520.     'Toggle image size': 'Click to toggle image size',
  8521.     'del': 'del',                 ///// delete, protect, move
  8522.     'delete': 'delete',
  8523.     'deleteHint': 'Delete %s',
  8524.     'undeleteShort': 'un',
  8525.     'UndeleteHint': 'Show the deletion history for %s',
  8526.     'protect': 'protect',
  8527.     'protectHint': 'Restrict editing rights to %s',
  8528.     'unprotectShort': 'un',
  8529.     'unprotectHint': 'Allow %s to be edited by anyone again',
  8530.     'move': 'move',
  8531.     'move page': 'move page',
  8532.     'MovepageHint': 'Change the title of %s',
  8533.     'edit': 'edit',               ///// edit articles and talk
  8534.     'edit article': 'edit article',
  8535.     'editHint': 'Change the content of %s',
  8536.     'edit talk': 'edit talk',
  8537.     'new': 'new',
  8538.     'new topic': 'new topic',
  8539.     'newSectionHint': 'Start a new section on %s',
  8540.     'null edit': 'null edit',
  8541.     'nullEditHint': 'Submit an edit to %s, making no changes ',
  8542.     'hist': 'hist',               ///// history, diffs, editors, related
  8543.     'history': 'history',
  8544.     'historyHint': 'List the changes made to %s',
  8545.     'last': 'last',
  8546.     'lastEdit': 'lastEdit',
  8547.     'mark patrolled': 'mark patrolled',
  8548.     'markpatrolledHint': 'Mark this edit as patrolled',
  8549.     'show last edit': 'most recent edit',
  8550.     'Show the last edit': 'Show the effects of the most recent change',
  8551.     'lastContrib': 'lastContrib',
  8552.     'last set of edits': 'latest edits',
  8553.     'lastContribHint': 'Show the net effect of changes made by the last editor',
  8554.     'cur': 'cur',
  8555.     'diffCur': 'diffCur',
  8556.     'Show changes since revision %s': 'Show changes since revision %s',
  8557.     '%s old': '%s old', // as in 4 weeks old
  8558.     'oldEdit': 'oldEdit',
  8559.     'purge': 'purge',
  8560.     'purgeHint': 'Demand a fresh copy of %s',
  8561.     'raw': 'source',
  8562.     'rawHint': 'Download the source of %s',
  8563.     'render': 'simple',
  8564.     'renderHint': 'Show a plain HTML version of %s',
  8565.     'Show the edit made to get revision': 'Show the edit made to get revision',
  8566.     'sinceMe': 'sinceMe',
  8567.     'changes since mine': 'diff my edit',
  8568.     'sinceMeHint': 'Show changes since my last edit',
  8569.     'Couldn\'t find an edit by %s\nin the last %s edits to\n%s': 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s',
  8570.     'eds': 'eds',
  8571.     'editors': 'editors',
  8572.     'editorListHint': 'List the users who have edited %s',
  8573.     'related': 'related',
  8574.     'relatedChanges': 'relatedChanges',
  8575.     'related changes': 'related changes',
  8576.     'RecentchangeslinkedHint': 'Show changes in articles related to %s',
  8577.     'editOld': 'editOld',          ///// edit old version, or revert
  8578.     'rv': 'rv',
  8579.     'revert': 'revert',
  8580.     'revertHint': 'Revert to %s',
  8581.     'defaultpopupRedlinkSummary': 'Removing link to empty page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8582.     'defaultpopupFixDabsSummary': 'Disambiguate [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8583.     'defaultpopupFixRedirsSummary': 'Redirect bypass from [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8584.     'defaultpopupExtendedRevertSummary': 'Revert to revision dated %s by %s, oldid %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8585.     'defaultpopupRevertToPreviousSummary': 'Revert to the revision prior to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8586.     'defaultpopupRevertSummary': 'Revert to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8587.     'defaultpopupQueriedRevertToPreviousSummary': 'Revert to the revision prior to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8588.     'defaultpopupQueriedRevertSummary': 'Revert to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8589.     'defaultpopupRmDabLinkSummary': 'Remove link to dab page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]',
  8590.     'Redirects': 'Redirects', // as in Redirects to ...
  8591.     ' to ': ' to ',           // as in Redirects to ...
  8592.     'Bypass redirect': 'Bypass redirect',
  8593.     'Fix this redirect': 'Fix this redirect',
  8594.     'disambig': 'disambig',          ///// add or remove dab etc.
  8595.     'disambigHint': 'Disambiguate this link to [[%s]]',
  8596.     'Click to disambiguate this link to:': 'Click to disambiguate this link to:',
  8597.     'remove this link': 'remove this link',
  8598.     'remove all links to this page from this article': 'remove all links to this page from this article',
  8599.     'remove all links to this disambig page from this article': 'remove all links to this disambig page from this article',
  8600.     'mainlink': 'mainlink',          ///// links, watch, unwatch
  8601.     'wikiLink': 'wikiLink',
  8602.     'wikiLinks': 'wikiLinks',
  8603.     'links here': 'links here',
  8604.     'whatLinksHere': 'whatLinksHere',
  8605.     'what links here': 'what links here',
  8606.     'WhatlinkshereHint': 'List the pages that are hyperlinked to %s',
  8607.     'unwatchShort': 'un',
  8608.     'watchThingy': 'watch',  // called watchThingy because {}.watch is a function
  8609.     'watchHint': 'Add %s to my watchlist',
  8610.     'unwatchHint': 'Remove %s from my watchlist',
  8611.     'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits',
  8612.     '%s seems to be the last editor to the page %s': '%s seems to be the last editor to the page %s',
  8613.     'rss': 'rss',
  8614.     /////////////////////////////////////
  8615.     // diff previews
  8616.     /////////////////////////////////////
  8617.     'Diff truncated for performance reasons': 'Diff truncated for performance reasons',
  8618.     'Old revision': 'Old revision',
  8619.     'New revision': 'New revision',
  8620.     'Something went wrong :-(': 'Something went wrong :-(',
  8621.     'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent',
  8622.     'Unknown date': 'Unknown date',
  8623.     /////////////////////////////////////
  8624.     // other special previews
  8625.     /////////////////////////////////////
  8626.     'Empty category': 'Empty category',
  8627.     'Category members (%s shown)': 'Category members (%s shown)',
  8628.     'No image links found': 'No image links found',
  8629.     'File links': 'File links',
  8630.     'No image found': 'No image found',
  8631.     'Image from Commons': 'Image from Commons',
  8632.     'Description page': 'Description page',
  8633.     /////////////////////////////////////
  8634.     // user-related actions and info
  8635.     /////////////////////////////////////
  8636.     'user': 'user',               ///// user page, talk, email, space
  8637.     'user page': 'user page',
  8638.     'user talk': 'user talk',
  8639.     'edit user talk': 'edit user talk',
  8640.     'leave comment': 'leave comment',
  8641.     'email': 'email',
  8642.     'email user': 'email user',
  8643.     'EmailuserHint': 'Send an email to %s',
  8644.     'space': 'space', // short form for userSpace link
  8645.     'PrefixindexHint': 'Show pages in the userspace of %s',
  8646.     'count': 'count',             ///// contributions, log
  8647.     'edit counter': 'edit counter',
  8648.     'editCounterLinkHint': 'Count the contributions made by %s',
  8649.     'contribs': 'contribs',
  8650.     'contributions': 'contributions',
  8651.     'deletedContribs': 'deleted contributions',
  8652.     'DeletedcontributionsHint': 'List deleted edits made by %s',
  8653.     'ContributionsHint': 'List the contributions made by %s',
  8654.     'log': 'log',
  8655.     'user log': 'user log',
  8656.     'userLogHint': 'Show %s\'s user log',
  8657.     'arin': 'ARIN lookup',             ///// ARIN lookup, block user or IP
  8658.     'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database',
  8659.     'unblockShort': 'un',
  8660.     'block': 'block',
  8661.     'block user': 'block user',
  8662.     'IpblocklistHint': 'Unblock %s',
  8663.     'BlockipHint': 'Prevent %s from editing',
  8664.     'block log': 'block log',
  8665.     'blockLogHint': 'Show the block log for %s',
  8666.     'protectLogHint': 'Show the protection log for %s',
  8667.     'pageLogHint': 'Show the page log for %s',
  8668.     'deleteLogHint': 'Show the deletion log for %s',
  8669.     'Invalid %s %s': 'The option %s is invalid: %s',
  8670.     'No backlinks found': 'No backlinks found',
  8671.     ' and more': ' and more',
  8672.     'undo': 'undo',
  8673.     'undoHint': 'undo this edit',
  8674.     'Download preview data': 'Download preview data',
  8675.     'Invalid or IP user': 'Invalid or IP user',
  8676.     'Not a registered username': 'Not a registered username',
  8677.     'BLOCKED': 'BLOCKED',
  8678.     ' edits since: ': ' edits since: ',
  8679.     /////////////////////////////////////
  8680.     // Autoediting
  8681.     /////////////////////////////////////
  8682.     'Enter a non-empty edit summary or press cancel to abort': 'Enter a non-empty edit summary or press cancel to abort',
  8683.     'Failed to get revision information, please edit manually.\n\n': 'Failed to get revision information, please edit manually.\n\n',
  8684.     'The %s button has been automatically clicked. Please wait for the next page to load.': 'The %s button has been automatically clicked. Please wait for the next page to load.',
  8685.     'Could not find button %s. Please check the settings in your javascript file.': 'Could not find button %s. Please check the settings in your javascript file.',
  8686.     /////////////////////////////////////
  8687.     // Popups setup
  8688.     /////////////////////////////////////
  8689.     'Open full-size image': 'Open full-size image',
  8690.     'zxy': 'zxy'
  8691. };
  8692.  
  8693.  
  8694. function popupString(str) {
  8695.     if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; }
  8696.     if (pg.string[str]) { return pg.string[str]; }
  8697.     return str;
  8698. }
  8699.  
  8700.  
  8701. function tprintf(str,subs) {
  8702.     if (typeof subs != typeof []) { subs = [subs]; }
  8703.     return simplePrintf(popupString(str), subs);
  8704. }
  8705.  
  8706.  
  8707. var WikiLookdb_pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.WikiLook.");
  8708.  
  8709. //////////////////////////////////////////////////////////////////////
  8710. // Data
  8711. //////////////////////////////////////////////////////////////////////
  8712.  
  8713. const WL_WikiLook = ",WikiLook,wikilook,WIKILOOK,"; 
  8714.  
  8715. //////////////////////////////////////////////////////////////////////
  8716. // Core Object
  8717. //////////////////////////////////////////////////////////////////////
  8718.  
  8719. WikiLook = function () {
  8720.     
  8721.     //Load up the English Wiktionary parser thingy..
  8722.     this._en_wikt = new WikiLook_en (this)
  8723.     this._currentVersion = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).getItemForID("wikilook@testpilot").version;
  8724.     this._WL_initialized = false;
  8725.     this._WL_enabled = true;
  8726.     
  8727.     
  8728.     this._WikiLookAutoAudio = null;
  8729.     this._WikiLookMouselookEnabled = null;
  8730.     this._WikiLookMouselookParser = null;
  8731.     this._WikiLookShiftEnabled = null;
  8732.     this._WikiLookShiftParser = null;
  8733.     this._WikiLookCtrlEnabled = null;
  8734.     this._WikiLookCtrlParser = null;
  8735.     this._WikiLookAltEnabled = null;
  8736.     this._WikiLookAltParser = null;
  8737.     this._CSS = '';
  8738.     this._currentParser = null;
  8739.     this._WL_ID = null;
  8740.     this._WL_unable = false; 
  8741.     this._engDefFound = false;
  8742.     this._wordMonTimer = null;    // word monitor timer object
  8743.     this._mainWindow = null;
  8744.     this._currentDoc = null;
  8745.     this._shiftKey = null;
  8746.     this._ctrlKey = null;
  8747.     this._altKey = null;
  8748.     this._eventButton= null;
  8749.     this._initialized = true;
  8750.     this._event=null;
  8751.     this._eventRangeParent = null;
  8752.     this._eventRangeOffset = null;
  8753.     this._eventTarget = null;
  8754.     this._event = null;
  8755.     this._eventClientX = null;
  8756.     this._eventClientY = null;
  8757.     this._wordX = null;
  8758.     this._wordY = null;
  8759.     this._currentWord = "";
  8760.     this._lastWord = "";
  8761.     this._wordMonTimer = null;
  8762.     this._pref_WordMonTimerDelay = 800;    // in miliseconds
  8763.     this._pref_HideWhenMouseMove = false;    // hide definition when mouse moves
  8764.     this._pref_WindowOffsetX = 6;        
  8765.     this._pref_WindowOffsetY = 6;        
  8766.     this._pref_BlockBasicWords = true;        
  8767.     this._divId = "WikiLook_overlay_layout";
  8768.     this._div = null;
  8769.     this._divIsDisplayed = false;
  8770.     this._showDefinition = false;
  8771.     this._audioLinkShown = false;
  8772.     this._isRequestFetching = false;
  8773.     this._statusImageId = "WikiLook_StatusImage";
  8774.     this._mainLanguage = "English";
  8775.     this._outTextForFormOf = "";
  8776.     this._mainLngFound = false;
  8777.     this._defFound = false;
  8778.     this._goForIt = false;
  8779.     this._thisIsAFormOf=false;
  8780.     this._thisIsAFormOfFormOf=false; //let entries like [[realised]], past form of [[realise]], alternate spelling of [[realize]], but still preventing more then 3 form of look ups
  8781.     this._outText = "";
  8782.     // color schemes
  8783.     this._linkColor = "#002BB8";
  8784.     this._backgroundColor = "#ffffe1";
  8785.     // AJAX object
  8786.     this._request = null;
  8787.     this.PMaker = null;
  8788.     this.PMakerFlag = false;
  8789.     this._DIVrepositioned=false;
  8790.     this.uid=0;
  8791.     //this._DIVrepositionedTo="";
  8792.     this._divOverWikiLinksDelay=0;
  8793.     this._divOverWikiLinksEnabled=true;
  8794.     this._DIVclass="";
  8795.     this._overWikiLink="";
  8796.     this._overWikiLinkWord="";
  8797.     this._overWikiLinkEvt="";
  8798.     // preference object
  8799.     this.mainDiv = null;
  8800.     this._divQ = new Array();
  8801.     this._divZIndex=10000;
  8802.     this._insideDivLookup = false;
  8803.     this._currentDiv = null;
  8804.     this._pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  8805.     this.init();
  8806. }
  8807.  
  8808.  
  8809. //OSD={}; OSD.WikiLook=WikiLook; OSD.WikiLook(); 
  8810.  
  8811. /**
  8812.  * Called at the end of constructor to finalize object...
  8813. **/
  8814. WikiLook.prototype.init = function() {
  8815.     if (this._WL_initialized == true) {
  8816.         return;
  8817.     }
  8818.     this._WL_initialized = true;
  8819.     this._WL_ID = ((new Date).getTime()).toString();
  8820.  
  8821. }
  8822.  
  8823. //////////////////////////////////////////////////////////////////////
  8824. // Global Raw Functions & Objects
  8825. //////////////////////////////////////////////////////////////////////
  8826.  
  8827. var WL_request = Object;
  8828.  
  8829. //////////////////////////////////////////////////////////////////////
  8830. // Event Handlers
  8831. //////////////////////////////////////////////////////////////////////
  8832.  
  8833. WikiLook.prototype.eventLoad = function(event) { WikiLook_Overlay.eventLoadImpl(event); } // fires once on each browser window open
  8834. WikiLook.prototype.eventLoadImpl = function(event) {
  8835.     var InitialRun = WikiLookdb_pref.getCharPref("WikiLookVersionNumber");
  8836.     WikiLookdb_pref.setCharPref("WikiLookVersionNumber", WikiLook_Overlay._currentVersion);
  8837.     this._currentParser = WikiLookdb_pref.getCharPref("WikiLookCtrlParser");
  8838.     this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopctl.css" /> ';
  8839.     setupPopups();
  8840.     autoEdit();
  8841.     this.loadPref();
  8842.     this.updateStatusImage();
  8843.     // test for mac: if(/Mac/.test(navigator.platform)) not working on all macs(at least on some 10.5)
  8844.     if (InitialRun=="0.0.0"&&(window.navigator.userAgent.indexOf("Mac OS")!=-1)){
  8845.         window.setTimeout(function() {    
  8846.             WikiLookdb_pref.setBoolPref("WikiLookCtrlEnabled", false);
  8847.             WikiLookdb_pref.setCharPref("WikiLookCtrlParser", 'http://uncyclopedia.wikia.com');
  8848.             WikiLookdb_pref.setCharPref("WikiLookAltParser", 'http://en.wikipedia.org');
  8849.             //alert("WikiLook parameters for Mac OS were set.");
  8850.         }, 500);
  8851.     }
  8852.     if (InitialRun!=this._currentVersion) {
  8853.         if(window.navigator.userAgent.indexOf("Mac OS")!=-1) {
  8854.             window.setTimeout(function() {
  8855.                 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
  8856.                 var wmed = wm.QueryInterface(Components.interfaces.nsIWindowMediator);
  8857.                 var win = wmed.getMostRecentWindow("navigator:browser");
  8858.                 var content = win.document.getElementById("content");
  8859.                 content.selectedTab = content.addTab("http://wikilook.mozdev.org/mac.html"); 
  8860.             }, 2250);
  8861.         } else {
  8862.             window.setTimeout(function() {
  8863.                 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
  8864.                 var wmed = wm.QueryInterface(Components.interfaces.nsIWindowMediator);
  8865.                 var win = wmed.getMostRecentWindow("navigator:browser");
  8866.                 var content = win.document.getElementById("content");
  8867.                 content.selectedTab = content.addTab("http://wikilook.mozdev.org/"); 
  8868.             }, 2250);
  8869.         }    
  8870.     }
  8871. }
  8872.  
  8873. WikiLook.prototype.eventUnload = function(event) { WikiLook_Overlay.eventUnloadImpl(event); } // fires once on each browser window close
  8874. WikiLook.prototype.eventUnloadImpl = function(event) {
  8875.     this.clearAll();
  8876. }
  8877.  
  8878. WikiLook.prototype.eventFocus = function(event) { WikiLook_Overlay.eventFocusImpl(event); }
  8879. WikiLook.prototype.eventFocusImpl = function(event) {
  8880.     //this.clearAll();
  8881.     //this._currentDoc = event.target;
  8882.  
  8883. }
  8884.  
  8885. WikiLook.prototype.eventBlur = function(event) { WikiLook_Overlay.eventBlurImpl(event); }
  8886. WikiLook.prototype.eventBlurImpl = function(event) {
  8887.     this.clearAll();
  8888. }
  8889.  
  8890. WikiLook.prototype.eventClick = function(event) { WikiLook_Overlay.eventClickImpl(event); }
  8891. WikiLook.prototype.eventClickImpl = function(event) {
  8892.     if (!this._WL_enabled||this._WL_unable) return;
  8893.     if (!(event.target.ownerDocument instanceof HTMLDocument)) return;
  8894.     if ((event.target.href != null)&& (event.button != 2)) return;
  8895.     if (event.target.id == "audioPlayback") return;
  8896.     if (event.target.id == "confDialog") {
  8897.         this.clearAll();
  8898.         if (window.navigator.userAgent.indexOf("Mac OS")!=-1) {
  8899.             window.openDialog('chrome://wikilook/content/optionsmac.xul', null, 'chrome,centerscreen,dependent');
  8900.         } else {
  8901.             window.openDialog('chrome://wikilook/content/optionsnorm.xul', null, 'chrome,centerscreen,dependent');
  8902.         }
  8903.         return;
  8904.     }
  8905.     if (this._DIVrepositioned) { 
  8906.         this._DIVrepositioned=false;
  8907.         /*this._currentDoc.getElementById(this._divQ[0]).style.zIndex=this._divZIndex + 1;
  8908.         ++this._divZIndex; */
  8909.         return; 
  8910.     }
  8911.     //gggggg
  8912.     if (!((this._eventButton==2&&this._altKey)||(this._eventButton==2&&this._ctrlKey)||(this._eventButton==2&&this._shiftKey))) {
  8913.         try {    
  8914.             if (event.originalTarget.parentNode.parentNode.id.indexOf("navpopup_maindiv")==0) {
  8915.                 if (event.originalTarget.parentNode.parentNode.id==this._divQ[0]) {
  8916.                     this.removeDivPrp(event.originalTarget.parentNode.parentNode.id);
  8917.                     this._divQ.splice(0,1);
  8918.                     //this._currentDoc.body.removeChild(this._currentDoc.getElementById(event.originalTarget.parentNode.parentNode.id));
  8919.                     return;
  8920.                 } else {
  8921.                     this._divQ.splice(this._divQ.indexOf(event.originalTarget.parentNode.parentNode.id),1)
  8922.                     this._divQ.unshift(event.originalTarget.parentNode.parentNode.id);
  8923.                     this._currentDoc.getElementById(event.originalTarget.parentNode.parentNode.id).style.zIndex=this._divZIndex + 1;
  8924.                     ++this._divZIndex; 
  8925.                     return;
  8926.                 }
  8927.             }
  8928.             if (event.originalTarget.parentNode.id.indexOf("navpopup_maindiv")==0) {    
  8929.                 if     (event.originalTarget.parentNode.id==this._divQ[0]) {
  8930.                     this.removeDivPrp(event.originalTarget.parentNode.id);
  8931.                     this._divQ.splice(0,1);
  8932.                     //this._currentDoc.body.removeChild(this._currentDoc.getElementById(event.originalTarget.parentNode.id));
  8933.                     return;
  8934.                 } else {
  8935.                     this._divQ.splice(this._divQ.indexOf(event.originalTarget.parentNode.id),1)
  8936.                     this._divQ.unshift(event.originalTarget.parentNode.id);
  8937.                     this._currentDoc.getElementById(event.originalTarget.parentNode.id).style.zIndex=this._divZIndex + 1;
  8938.                     ++this._divZIndex; 
  8939.                     return;    
  8940.                 }
  8941.             }
  8942.             if (typeof event.originalTarget.childNodes[1]!="undefined"&&typeof event.originalTarget.childNodes[1].offsetParent!="undefined"){
  8943.                 if (event.originalTarget.childNodes[1].offsetParent.id.indexOf("navpopup_maindiv")==0) {    
  8944.                     if     (event.originalTarget.childNodes[1].offsetParent.id==this._divQ[0]) {
  8945.                         this.removeDivPrp(event.originalTarget.childNodes[1].offsetParent.id);
  8946.                         this._divQ.splice(0,1);
  8947.                         //this._currentDoc.body.removeChild(this._currentDoc.getElementById(event.originalTarget.childNodes[1].offsetParent.id));
  8948.                         return;
  8949.                     } else {
  8950.                         this._divQ.splice(this._divQ.indexOf(event.originalTarget.childNodes[1].offsetParent.id),1)
  8951.                         this._divQ.unshift(event.originalTarget.childNodes[1].offsetParent.id);
  8952.                         this._currentDoc.getElementById(event.originalTarget.childNodes[1].offsetParent.id).style.zIndex=this._divZIndex + 1;
  8953.                         ++this._divZIndex; 
  8954.                         return;    
  8955.                     }
  8956.                 }
  8957.             }    
  8958.             if (event.originalTarget.offsetParent.id.indexOf("navpopup_maindiv")==0) {    
  8959.                 if     (event.originalTarget.offsetParent.id==this._divQ[0]) {
  8960.                     //this._currentDoc.body.removeChild(this._currentDoc.getElementById(event.originalTarget.offsetParent.id));
  8961.                     this.removeDivPrp(event.originalTarget.offsetParent.id);
  8962.                     this._divQ.splice(0,1);
  8963.                     return;
  8964.                 } else {
  8965.                     this._divQ.splice(this._divQ.indexOf(event.originalTarget.offsetParent.id),1)
  8966.                     this._divQ.unshift(event.originalTarget.offsetParent.id);
  8967.                     this._currentDoc.getElementById(event.originalTarget.offsetParent.id).style.zIndex=this._divZIndex + 1;
  8968.                     ++this._divZIndex; 
  8969.                     return;    
  8970.                 }
  8971.             }
  8972.             
  8973.             //this._currentDoc.body.removeChild(this._currentDoc.getElementById(this._divQ[0]));
  8974.             this.removeDivPrp(this._divQ[0]);
  8975.             this._divQ.splice(0,1);
  8976.             return;
  8977.         } catch (err) { 
  8978.         }
  8979.     }
  8980.     if ((this._eventButton==2&&this._altKey)||(this._eventButton==2&&this._ctrlKey)||(this._eventButton==2&&this._shiftKey)) {
  8981.         try {    
  8982.             if (typeof event.originalTarget.childNodes[1]!="undefined"&&typeof event.originalTarget.childNodes[1].offsetParent!="undefined") {
  8983.                 if (event.originalTarget.parentNode.parentNode.id.indexOf("navpopup_maindiv")==0||event.originalTarget.parentNode.id.indexOf("navpopup_maindiv")==0||event.originalTarget.childNodes[1].offsetParent.id.indexOf("navpopup_maindiv")==0||event.originalTarget.offsetParent.id.indexOf("navpopup_maindiv")==0) {
  8984.                     this._insideDivLookup=true;
  8985.                     this.clearAllButScreen();    
  8986.                 } else {
  8987.                     this._insideDivLookup=false;
  8988.                 }
  8989.             } else {    
  8990.                 if (event.originalTarget.parentNode.parentNode.id.indexOf("navpopup_maindiv")==0||event.originalTarget.parentNode.id.indexOf("navpopup_maindiv")==0||event.originalTarget.offsetParent.id.indexOf("navpopup_maindiv")==0) {
  8991.                     this._insideDivLookup=true;
  8992.                     this.clearAllButScreen();    
  8993.                 } else {
  8994.                     this._insideDivLookup=false;
  8995.                 }
  8996.             }    
  8997.         } catch (err) { this._insideDivLookup=false; }        
  8998.     }    
  8999.     if ( this._eventTarget.tagName == "SELECT") return;
  9000.     this.clearWordMonTimer();
  9001.     this._currentDoc = this.getDoc(event);
  9002.     this._eventTarget = event.target;
  9003.     //if ( this._eventTarget.tagName != "SELECT") {
  9004.         this._eventRangeParent = event.rangeParent;
  9005.         this._eventRangeOffset = event.rangeOffset;
  9006.         this._eventClientX = event.clientX;
  9007.         this._eventClientY = event.clientY;
  9008.         this._shiftKey = event.shiftKey;
  9009.         this._ctrlKey = event.ctrlKey;
  9010.         this._altKey = event.altKey;
  9011.         this._eventButton = event.button;        
  9012.         if (this._eventButton==2&&(this._altKey||this._ctrlKey||this._shiftKey)) {
  9013.             this.MouseMoveMon(event);
  9014.         } else {
  9015.             if (this._eventButton==2) return;
  9016.             this._currentDoc = this.getDoc(event);
  9017.             //this.clearAll();
  9018.             
  9019.         }
  9020. }
  9021.  
  9022. WikiLook.prototype.eventRightClick = function(event) { WikiLook_Overlay.eventRightClickImpl(event); }
  9023. WikiLook.prototype.eventRightClickImpl = function(event) {
  9024.     if (!this._WL_enabled||this._WL_unable) return;
  9025.     if (!(event.target.ownerDocument instanceof HTMLDocument)) return;
  9026.     if ((event.target.href != null)&& (event.button != 2)) return;
  9027.     if (event.target.id == "audioPlayback") return;
  9028.     if ( this._eventTarget.tagName == "SELECT") return;
  9029.     /*if (this._pref_HideWhenMouseMove || this._isRequestFetching ) {
  9030.         //if (this._defFound==false) this.clearAll();
  9031.         //this.clearWordMonTimer();
  9032.     } else {
  9033.         //this.clearWordMonTimer();
  9034.     }*/
  9035.     this.clearWordMonTimer();
  9036.     this._currentDoc = this.getDoc(event);
  9037.     this._eventTarget = event.target;
  9038.         this._eventRangeParent = event.rangeParent;
  9039.         this._eventRangeOffset = event.rangeOffset;
  9040.         this._eventClientX = event.clientX;
  9041.         this._eventClientY = event.clientY;
  9042.         this._shiftKey = event.shiftKey;
  9043.         this._ctrlKey = event.ctrlKey;
  9044.         this._altKey = event.altKey;
  9045.         this._eventButton = event.button;        
  9046.         if (this._eventButton==2&&(this._altKey||this._ctrlKey||this._shiftKey)) {    
  9047.         ////////////////////
  9048.             if (!this._WL_enabled) return;
  9049.             this._currentWord = this.getCurrentWord(this._eventRangeParent,this._eventRangeOffset,this._eventTarget);
  9050.             if (this._currentWord == null || this._currentWord.length < 1) return;
  9051.             this._currentWord = this.trim(this._currentWord);
  9052.             this._lastWord = this._currentWord + this._shiftKey.toString() + this._ctrlKey.toString() + this._altKey.toString() ;
  9053.             if (WL_WikiLook.indexOf(","+this._currentWord+",") != -1) {
  9054.                 event.preventDefault();
  9055.                 event.stopPropagation();
  9056.                 this.showDiv();
  9057.                 return;
  9058.             }
  9059.             if ( this._currentWord != null && this._currentWord.length > 0) {
  9060.                 if (this._eventButton==2&&this._shiftKey) { //Shift key
  9061.                     if (!WikiLookdb_pref.getBoolPref("WikiLookShiftEnabled")) { return};
  9062.                     event.preventDefault();
  9063.                     event.stopPropagation();
  9064.                 } else {
  9065.                     if (this._eventButton==2&&this._altKey) { //ALT key
  9066.                         if (!WikiLookdb_pref.getBoolPref("WikiLookAltEnabled")) { return};
  9067.                         event.preventDefault();
  9068.                         event.stopPropagation();
  9069.                     }  else { 
  9070.                         if (this._eventButton==2&&this. _ctrlKey) { //CTRL key
  9071.                             if (!WikiLookdb_pref.getBoolPref("WikiLookCtrlEnabled")) { return};
  9072.                             event.preventDefault();
  9073.                             event.stopPropagation();
  9074.                         }     
  9075.                     }    
  9076.                 }    
  9077.             }
  9078.         }
  9079. }
  9080.  
  9081. WikiLook.prototype.eventMouseDown = function(event) { WikiLook_Overlay.eventMouseDownImpl(event); }
  9082. WikiLook.prototype.eventMouseDownImpl = function(event) {
  9083.     if (!this._WL_enabled||this._WL_unable) return;
  9084.     if (!(event.target.ownerDocument instanceof HTMLDocument)) return;
  9085.     if ((event.target.href != null)&& (event.button != 2)) return;
  9086.     if (event.target.id == "audioPlayback") return;
  9087.     if ( this._eventTarget.tagName == "SELECT") return;
  9088.     /*if (this._pref_HideWhenMouseMove || this._isRequestFetching ) {
  9089.         //if (this._defFound==false) this.clearAll();
  9090.         //this.clearWordMonTimer();
  9091.     } else {
  9092.         //this.clearWordMonTimer();
  9093.     }*/
  9094.     this.clearWordMonTimer();
  9095.     this._currentDoc = this.getDoc(event);
  9096.     this._eventTarget = event.target;
  9097.         this._eventRangeParent = event.rangeParent;
  9098.         this._eventRangeOffset = event.rangeOffset;
  9099.         this._eventClientX = event.clientX;
  9100.         this._eventClientY = event.clientY;
  9101.         this._shiftKey = event.shiftKey;
  9102.         this._ctrlKey = event.ctrlKey;
  9103.         this._altKey = event.altKey;
  9104.         this._eventButton = event.button;        
  9105.         if (this._eventButton==2&&(this._altKey||this._ctrlKey||this._shiftKey)) {    
  9106.         ////////////////////
  9107.             if (!this._WL_enabled) return;
  9108.             this._currentWord = this.getCurrentWord(this._eventRangeParent,this._eventRangeOffset,this._eventTarget);
  9109.             if (this._currentWord == null || this._currentWord.length < 1) return;
  9110.             this._currentWord = this.trim(this._currentWord);
  9111.             this._lastWord = this._currentWord + this._shiftKey.toString() + this._ctrlKey.toString() + this._altKey.toString() ;
  9112.             if (WL_WikiLook.indexOf(","+this._currentWord+",") != -1) {
  9113.                 event.preventDefault();
  9114.                 event.stopPropagation();
  9115.                 this.showDiv();
  9116.                 return;
  9117.             }
  9118.             if ( this._currentWord != null && this._currentWord.length > 0) {
  9119.                 if (this._eventButton==2&&this._shiftKey) { //Shift key
  9120.                     if (!WikiLookdb_pref.getBoolPref("WikiLookShiftEnabled")) { return};
  9121.                     event.preventDefault();
  9122.                     event.stopPropagation();
  9123.                 } else {
  9124.                     if (this._eventButton==2&&this._altKey) { //ALT key
  9125.                         if (!WikiLookdb_pref.getBoolPref("WikiLookAltEnabled")) { return};
  9126.                         event.preventDefault();
  9127.                         event.stopPropagation();
  9128.                     }  else { 
  9129.                         if (this._eventButton==2&&this._ctrlKey) { //CTRL key
  9130.                             if (!WikiLookdb_pref.getBoolPref("WikiLookCtrlEnabled")) { return};
  9131.                             event.preventDefault();
  9132.                             event.stopPropagation();
  9133.                         }     
  9134.                     }    
  9135.                 }    
  9136.             }
  9137.         }
  9138. }
  9139.  
  9140. WikiLook.prototype.eventMouseMove = function(event) { WikiLook_Overlay.eventMouseMoveImpl(event); }
  9141. WikiLook.prototype.eventMouseMoveImpl = function(event) {
  9142.     if (!this._WL_enabled||this._WL_unable) return;
  9143.     if (!(event.target.ownerDocument instanceof HTMLDocument)) return;
  9144.     if (this._pref_HideWhenMouseMove || this._isRequestFetching ) {
  9145.         //if (this._defFound) return;
  9146.         //if (this._defFound==false) this.clearAll(); //kills incomplete div on mousemove
  9147.         this.clearWordMonTimer();
  9148.     } else {
  9149.         this.clearWordMonTimer();
  9150.         //this.clearRequest();
  9151.     }
  9152.  
  9153.     // WL_currentDoc = event.target.ownerDocument;
  9154.     this._currentDoc = this.getDoc(event);
  9155.     this._eventTarget = event.target;
  9156.     if ( this._eventTarget.tagName != "SELECT") {
  9157.         this._shiftKey = event.shiftKey;
  9158.         this._ctrlKey = event.ctrlKey;
  9159.         this._altKey = event.altKey;
  9160.         this._eventRangeParent = event.rangeParent;
  9161.         this._eventRangeOffset = event.rangeOffset;
  9162.         this._eventClientX = event.clientX;
  9163.         this._eventClientY = event.clientY;
  9164.         this._event=event;
  9165.         this._wordMonTimer = setTimeout("WikiLook_Overlay.MouseMoveMon(WikiLook_Overlay._event)",this._pref_WordMonTimerDelay);
  9166.     
  9167.     }
  9168.     
  9169. }
  9170.  
  9171. WikiLook.prototype.eventScroll = function(event) { WikiLook_Overlay.eventScrollImpl(event); }
  9172. WikiLook.prototype.eventScrollImpl = function(event) {
  9173.     if (!this._WL_enabled) return;
  9174.     //if (!this._showDefinition) this.clearAll();
  9175. }
  9176.  
  9177. WikiLook.prototype.eventClickStatus = function(event) { WikiLook_Overlay.eventClickStatusImpl(event); }
  9178. WikiLook.prototype.eventClickStatusImpl = function(event) {
  9179.  
  9180. //    evt.preventDefault();
  9181. //    evt.stopPropagation();
  9182.     if (event.button == 0){ //left click
  9183.         this._WL_enabled = !this._WL_enabled;
  9184.         WikiLookdb_pref.setBoolPref("WL_enabled", this._WL_enabled);
  9185.         
  9186.         // when turned off
  9187.         if (!this._WL_enabled) {
  9188.             this._pref.setBoolPref("extensions.wikilook.enabled", this._WL_enabled);
  9189.             this.clearAll();
  9190.         }
  9191.         this.updateStatusImage();
  9192.  
  9193.     } else {
  9194.         if (event.button == 2) // right-click
  9195.         this._WL_enabled = true;
  9196.         WikiLookdb_pref.setBoolPref("WL_enabled", this._WL_enabled);
  9197.         var statusImg = document.getElementById("WikiLook_StatusImage");
  9198.         statusImg.src = "chrome://wikilook/skin/wiki_on.gif";
  9199.         statusImg.tooltipText = "WikiLook is on.\nLeft-click to toggle.\nRight-click to open Options.";
  9200.         this.clearAll();
  9201.         if (window.navigator.userAgent.indexOf("Mac OS")!=-1) {
  9202.             window.openDialog('chrome://wikilook/content/optionsmac.xul', null, 'chrome,centerscreen,dependent');
  9203.         } else {
  9204.             window.openDialog('chrome://wikilook/content/optionsnorm.xul', null, 'chrome,centerscreen,dependent');
  9205.         }
  9206.     }
  9207. }
  9208.  
  9209. //////////////////////////////////////////////////////////////////////
  9210. // Core Functions
  9211. //////////////////////////////////////////////////////////////////////
  9212.  
  9213. WikiLook.prototype.updateStatusImage = function() {
  9214.     var statusImg = document.getElementById("WikiLook_StatusImage");
  9215.     if (this._WL_enabled) {
  9216.         statusImg.src = "chrome://wikilook/skin/wiki_on.gif";
  9217.         statusImg.tooltipText = "WikiLook is on.\nLeft-click to toggle.\nRight-click to open Options."
  9218.     } else {
  9219.         statusImg.src = "chrome://wikilook/skin/wiki_off.gif";
  9220.         statusImg.tooltipText = "WikiLook is off.\nLeft-click to toggle.\nRight-click to open Options."
  9221.     }
  9222. }
  9223.  
  9224. WikiLook.prototype.grabOverWikiLinks = function() {
  9225.     this._divOverWikiLinksEnabled=WikiLookdb_pref.getBoolPref("divOverWikiLinksEnabled");
  9226.     this._divOverWikiLinksDelay=WikiLookdb_pref.getIntPref("divOverWikiLinksDelay");
  9227. }
  9228.  
  9229.  
  9230. WikiLook.prototype.loadPref = function() {
  9231.  
  9232. //popupDelay = WikiLookdb_pref.getIntPref("popupDelay");
  9233. //popupHideDelay = WikiLookdb_pref.getIntPref("popupHideDelay");
  9234. simplePopups = WikiLookdb_pref.getBoolPref("simplePopups");
  9235. popupStructure = WikiLookdb_pref.getCharPref("popupStructure");
  9236. popupActionsMenu = WikiLookdb_pref.getBoolPref("popupActionsMenu");
  9237. popupSetupMenu = WikiLookdb_pref.getBoolPref("popupSetupMenu");
  9238. popupAdminLinks = WikiLookdb_pref.getBoolPref("popupAdminLinks");
  9239. popupShortcutKeys = WikiLookdb_pref.getBoolPref("popupShortcutKeys");
  9240. popupHistoricalLinks = WikiLookdb_pref.getBoolPref("popupHistoricalLinks");
  9241. popupOnlyArticleLinks = WikiLookdb_pref.getBoolPref("popupOnlyArticleLinks");
  9242. removeTitles = WikiLookdb_pref.getBoolPref("removeTitles");
  9243. popupMaxWidth = WikiLookdb_pref.getIntPref("popupMaxWidth");
  9244. popupInitialWidth = WikiLookdb_pref.getBoolPref("popupInitialWidth");
  9245. popupSimplifyMainLink = WikiLookdb_pref.getBoolPref("popupSimplifyMainLink");
  9246. popupAppendRedirNavLinks = WikiLookdb_pref.getBoolPref("popupAppendRedirNavLinks");
  9247. popupTocLinks = WikiLookdb_pref.getBoolPref("popupTocLinks");
  9248. popupSubpopups = WikiLookdb_pref.getBoolPref("popupSubpopups");
  9249. popupDragHandle = WikiLookdb_pref.getBoolPref("popupDragHandle");
  9250. popupLazyPreviews = WikiLookdb_pref.getBoolPref("popupLazyPreviews");
  9251. popupLazyDownloads = WikiLookdb_pref.getBoolPref("popupLazyDownloads");
  9252. popupAllDabsStubs = WikiLookdb_pref.getBoolPref("popupAllDabsStubs");
  9253. popupDebugging = WikiLookdb_pref.getBoolPref("popupDebugging");
  9254. popupAdjustDiffDates = WikiLookdb_pref.getBoolPref("popupAdjustDiffDates");
  9255. popupActiveNavlinks = WikiLookdb_pref.getBoolPref("popupActiveNavlinks");
  9256. popupModifier = WikiLookdb_pref.getBoolPref("popupModifier");
  9257. popupModifierAction = WikiLookdb_pref.getCharPref("popupModifierAction");
  9258. popupImages = WikiLookdb_pref.getBoolPref("popupImages");
  9259. imagePopupsForImages = WikiLookdb_pref.getBoolPref("imagePopupsForImages");
  9260. popupNeverGetThumbs = WikiLookdb_pref.getBoolPref("popupNeverGetThumbs");
  9261. popupImagesFromThisWikiOnly = WikiLookdb_pref.getBoolPref("popupImagesFromThisWikiOnly");
  9262. popupMinImageWidth = WikiLookdb_pref.getIntPref("popupMinImageWidth");
  9263. popupLoadImagesSequentially = WikiLookdb_pref.getBoolPref("popupLoadImagesSequentially");
  9264. popupThumbAction = WikiLookdb_pref.getCharPref("popupThumbAction");
  9265. popupImageSize = WikiLookdb_pref.getIntPref("popupImageSize");
  9266. popupFixRedirs = WikiLookdb_pref.getBoolPref("popupFixRedirs");
  9267. popupRedirAutoClick = WikiLookdb_pref.getCharPref("popupRedirAutoClick");
  9268. popupFixDabs = WikiLookdb_pref.getBoolPref("popupFixDabs");
  9269. popupRevertSummaryPrompt = WikiLookdb_pref.getBoolPref("popupRevertSummaryPrompt");
  9270. popupMinorReverts = WikiLookdb_pref.getBoolPref("popupMinorReverts");
  9271. popupRedlinkRemoval = WikiLookdb_pref.getBoolPref("popupRedlinkRemoval");
  9272. //popupWatchDisambiggedPages = WikiLookdb_pref.getBoolPref("popupWatchDisambiggedPages");
  9273. //popupWatchRedirredPages = WikiLookdb_pref.getBoolPref("popupWatchRedirredPages");
  9274. popupDabWiktionary = WikiLookdb_pref.getCharPref("popupDabWiktionary");
  9275. popupNavLinks = WikiLookdb_pref.getBoolPref("popupNavLinks");
  9276. popupNavLinkSeparator = WikiLookdb_pref.getCharPref("popupNavLinkSeparator");
  9277. popupLastEditLink = WikiLookdb_pref.getBoolPref("popupLastEditLink");
  9278. popupEditCounterTool = WikiLookdb_pref.getCharPref("popupEditCounterTool");
  9279. popupEditCounterUrl = WikiLookdb_pref.getCharPref("popupEditCounterUrl");
  9280. popupExtraUserMenu = WikiLookdb_pref.getCharPref("popupExtraUserMenu");
  9281. popupPreviews = WikiLookdb_pref.getBoolPref("popupPreviews");
  9282. popupSummaryData = WikiLookdb_pref.getBoolPref("popupSummaryData");
  9283. popupMaxPreviewSentences = WikiLookdb_pref.getIntPref("popupMaxPreviewSentences");
  9284. popupMaxPreviewCharacters = WikiLookdb_pref.getIntPref("popupMaxPreviewCharacters");
  9285. popupLastModified = WikiLookdb_pref.getBoolPref("popupLastModified");
  9286. popupPreviewKillTemplates = WikiLookdb_pref.getBoolPref("popupPreviewKillTemplates");
  9287. popupPreviewRawTemplates = WikiLookdb_pref.getBoolPref("popupPreviewRawTemplates");
  9288. popupPreviewFirstParOnly = WikiLookdb_pref.getBoolPref("popupPreviewFirstParOnly");
  9289. popupPreviewCutHeadings = WikiLookdb_pref.getBoolPref("popupPreviewCutHeadings");
  9290. popupPreviewButton = WikiLookdb_pref.getBoolPref("popupPreviewButton");
  9291. popupPreviewButtonEvent = WikiLookdb_pref.getCharPref("popupPreviewButtonEvent");
  9292. popupDiffContextCharacters = WikiLookdb_pref.getIntPref("popupDiffContextCharacters");
  9293. popupPreviewDiffs = WikiLookdb_pref.getBoolPref("popupPreviewDiffs");
  9294. popupDiffMaxLines = WikiLookdb_pref.getIntPref("popupDiffMaxLines");
  9295. popupDiffContextLines = WikiLookdb_pref.getIntPref("popupDiffContextLines");
  9296. popupDiffContextCharacters = WikiLookdb_pref.getIntPref("popupDiffContextCharacters");
  9297. popupDiffDates = WikiLookdb_pref.getBoolPref("popupDiffDates");
  9298. popupDiffDatePrinter = WikiLookdb_pref.getCharPref("popupDiffDatePrinter");
  9299. //pref("extensions.WikiLook.popupFixDabsSummary",           popupString('defaultpopupFixDabsSummary') );
  9300. //pref("extensions.WikiLook.popupExtendedRevertSummary",    popupString('defaultpopupExtendedRevertSummary') );
  9301. //popupTimeOffset = WikiLookdb_pref.getIntPref("popupTimeOffset");
  9302. //pref("extensions.WikiLook.popupRevertSummary",            popupString('defaultpopupRevertSummary') );
  9303. //pref("extensions.WikiLook.popupRevertToPreviousSummary",  popupString('defaultpopupRevertToPreviousSummary') );
  9304. //pref("extensions.WikiLook.popupQueriedRevertSummary",            popupString('defaultpopupQueriedRevertSummary') );
  9305. //pref("extensions.WikiLook.popupQueriedRevertToPreviousSummary",  popupString('defaultpopupQueriedRevertToPreviousSummary') );
  9306. //pref("extensions.WikiLook.popupFixRedirsSummary",         popupString('defaultpopupFixRedirsSummary') );
  9307. //pref("extensions.WikiLook.popupRedlinkSummary",           popupString('defaultpopupRedlinkSummary') );
  9308. //pref("extensions.WikiLook.popupRmDabLinkSummary",         popupString('defaultpopupRmDabLinkSummary') );
  9309.  
  9310. popupCookies = WikiLookdb_pref.getBoolPref("popupCookies");
  9311. popupHistoryLimit = WikiLookdb_pref.getIntPref("popupHistoryLimit");
  9312. //popupFilters = WikiLookdb_pref.getCharPref("popupFilters");
  9313. //extraPopupFilters = WikiLookdb_pref.getCharPref("extraPopupFilters");
  9314. popupOnEditSelection = WikiLookdb_pref.getCharPref("popupOnEditSelection");
  9315. popupPreviewHistory = WikiLookdb_pref.getBoolPref("popupPreviewHistory");
  9316. popupImageLinks = WikiLookdb_pref.getBoolPref("popupImageLinks");
  9317. popupCategoryMembers = WikiLookdb_pref.getBoolPref("popupCategoryMembers");
  9318. popupUserInfo = WikiLookdb_pref.getBoolPref("popupUserInfo");
  9319. popupHistoryPreviewLimit = WikiLookdb_pref.getIntPref("popupHistoryPreviewLimit");
  9320. popupContribsPreviewLimit = WikiLookdb_pref.getIntPref("popupContribsPreviewLimit");
  9321. popupNewWindows = WikiLookdb_pref.getBoolPref("popupNewWindows");
  9322. //popupLinksNewWindow = WikiLookdb_pref.getCharPref("popupLinksNewWindow");
  9323. popupDabRegexp = WikiLookdb_pref.getCharPref("popupDabRegexp");
  9324. popupStubRegexp = WikiLookdb_pref.getCharPref("popupStubRegexp");
  9325. popupImageVarsRegexp = WikiLookdb_pref.getCharPref("popupImageVarsRegexp");
  9326.  
  9327.  
  9328.  
  9329.  
  9330.  
  9331.  
  9332.  
  9333.     /*popupRedlinkRemoval== WikiLookdb_pref.getBoolPref("popupRedlinkRemoval");
  9334.     popupMaxWidth = WikiLookdb_pref.getIntPref("popupMaxWidth");
  9335.     popupMaxPreviewSentences = WikiLookdb_pref.getIntPref("popupMaxPreviewSentences"); 
  9336.     popupMaxPreviewCharacters = WikiLookdb_pref.getIntPref("popupMaxPreviewCharacters");
  9337.     popupPreviewFirstParOnly = WikiLookdb_pref.getBoolPref("popupPreviewFirstParOnly");
  9338.     popupImageSize== WikiLookdb_pref.getIntPref("popupImageSize");
  9339.     
  9340.     
  9341.     
  9342.     
  9343.     popupMinImageWidth=40;
  9344.     popupShowNonCommonsImages=true;
  9345.     popupActionsMenu=false;
  9346.     popupSetupMenu=false;
  9347.     popupImageLinks=false;*/
  9348.     this._WikiLookAutoAudio = WikiLookdb_pref.getBoolPref("WikiLookAutoAudio"); 
  9349.     this._WikiLookMouselookEnabled = WikiLookdb_pref.getBoolPref("WikiLookMouselookEnabled");
  9350.     this._WikiLookMouselookParser = WikiLookdb_pref.getCharPref("WikiLookMouselookParser");
  9351.     this._WikiLookShiftEnabled = WikiLookdb_pref.getBoolPref("WikiLookShiftEnabled");
  9352.     this._WikiLookShiftParser = WikiLookdb_pref.getCharPref("WikiLookShiftParser");
  9353.     this._WikiLookCtrlEnabled = WikiLookdb_pref.getBoolPref("WikiLookCtrlEnabled");
  9354.     this._WikiLookCtrlParser = WikiLookdb_pref.getCharPref("WikiLookCtrlParser");
  9355.     this._WikiLookAltEnabled = WikiLookdb_pref.getBoolPref("WikiLookAltEnabled");
  9356.     this._WikiLookAltParser = WikiLookdb_pref.getCharPref("WikiLookAltParser");    
  9357.     this._WL_enabled = WikiLookdb_pref.getBoolPref("WL_enabled");
  9358.     this._mainLanguage = WikiLookdb_pref.getCharPref("WikiLookMainLanguage");
  9359. }
  9360.  
  9361. WikiLook.prototype.clearKeys = function() { 
  9362.     this._shiftKey = null;
  9363.     this._ctrlKey = null;
  9364.     this._altKey = null;
  9365.     this._eventButton= null;    
  9366. }
  9367.  
  9368. WikiLook.prototype.clearAllButScreen = function() {
  9369.     this._goForIt = false;
  9370.     this._outTextForFormOf = "";
  9371.     this._mainLngFound=false;
  9372.     this._defFound = false;
  9373.     this.clearWordMonTimer();
  9374.     this.clearRequest();
  9375.     this._currentDoc = null;
  9376.     //this._currentWord = null;
  9377.     this._engDefFound = false;
  9378.     this._thisIsAFormOf=false;
  9379.     this._thisIsAFormOfFormOf=false;    
  9380.     this._audioLinkShown=false;
  9381.     this._showDefinition = false;
  9382.     this._divIsDisplayed=false;
  9383.     //this._insideDivLookup=false;
  9384.     //rmPopupShortcuts();
  9385.     this.clearKeys();    
  9386. }
  9387.  
  9388. WikiLook.prototype.clearAll = function() { // get ready for new state
  9389.     this.clearDisplay();
  9390.     this._goForIt = false;
  9391.     this._outTextForFormOf = "";
  9392.     this._mainLngFound=false;
  9393.     this._defFound = false;
  9394.     this.clearWordMonTimer();
  9395.     this.clearRequest();
  9396.     this._currentDoc = null;
  9397.     //this._currentWord = null;
  9398.     this._engDefFound = false;
  9399.     this._divIsDisplayed=false;
  9400.     //rmPopupShortcuts();
  9401.     this._insideDivLookup=false;
  9402.     this.clearKeys();    
  9403. }
  9404.  
  9405. WikiLook.prototype.clearWordMonTimer = function() {
  9406.     if (this._wordMonTimer != null) {
  9407.         clearTimeout(this._wordMonTimer);
  9408.         this._wordMonTimer = null;
  9409.     }
  9410. }
  9411.  
  9412. WikiLook.prototype.clearDisplay = function() {
  9413.     //killPopup();
  9414.     this.removeAllDivs();
  9415.     this._thisIsAFormOf=false;
  9416.     this._thisIsAFormOfFormOf=false;    
  9417.     this._audioLinkShown=false;
  9418.     this._showDefinition = false;
  9419. }
  9420.  
  9421.  
  9422. WikiLook.prototype.removeAllDivs = function () {
  9423.     while(this._divQ[0]!=null){
  9424.         try {
  9425.             //this._currentDoc.body.removeChild(this._currentDoc.getElementById(this._divQ[0]));
  9426.             this.removeDivPrp(this._divQ[0]);
  9427.         } catch(err) { 
  9428.             if (this._currentDoc.getElementById(this._divId) != null) {
  9429.                 var t=this._currentDoc.getElementById(this._divId).parentNode;
  9430.                 t.removeChild(this._currentDoc.getElementById(this._divId));
  9431.                 this._currentDoc.removeChild(this._divId);
  9432.             }
  9433.         }
  9434.         this._divQ.splice(0,1);
  9435.     }
  9436.     //this.clearAllButScreen();    
  9437. }
  9438.  
  9439. WikiLook.prototype.clearRequest = function () {
  9440.     if (this._isRequestFetching) {
  9441.         this._isRequestFetching = false;
  9442.     }
  9443.     if (WL_request != null)    {
  9444.         try {
  9445.             WL_request.abort();    
  9446.         }
  9447.         catch (e) {
  9448.         }
  9449.         WL_request = null
  9450.     }
  9451. }
  9452.  
  9453. WikiLook.prototype.getDoc = function(event) {
  9454.     return event.target.ownerDocument;
  9455.     /*return window._content.document;
  9456.     return content.document;
  9457.     return //WL_currentDoc = content.document;*/
  9458. }
  9459.  
  9460. WikiLook.prototype.MouseMoveMon = function(evt) { // Mouse Movement Monitor
  9461.     if (!this._WL_enabled) return;
  9462.     this._currentWord = this.getCurrentWord(this._eventRangeParent,this._eventRangeOffset,this._eventTarget);
  9463.     if (this._currentWord == null || this._currentWord.length < 1) return;
  9464.     this._currentWord = this.trim(this._currentWord);
  9465.     this._lastWord = this._currentWord + this._shiftKey.toString() + this._ctrlKey.toString() + this._altKey.toString() ;
  9466.  
  9467.     
  9468.     if (WL_WikiLook.indexOf(","+this._currentWord+",") != -1) {
  9469.         this._showDefinition = true;
  9470.         this._isRequestFetching = true;
  9471.         if(!this.attachDiv()) return;
  9472.         this._div.style.left = this.getNewWindowX() + "px";
  9473.         this._div.style.top = this.getNewWindowY() + "px";
  9474.         this._div.innerHTML = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopmic.css" /> WikiLook is your favorite add-on! :-)';
  9475.         evt.preventDefault();
  9476.         evt.stopPropagation();
  9477.         this.showDiv();
  9478.         return;
  9479.     }
  9480.     // Valid word?
  9481.     if ( this._currentWord != null && this._currentWord.length > 0) {
  9482.         this._currentWord=this._currentWord.replace(/'s$/, "" )
  9483.         this._currentWord=this._currentWord.replace(/ΓÇÖs$/, "" )
  9484.         this._currentWord=this._currentWord.replace(/'(\S+)'/g, "$1")
  9485.         this._currentWord=this._currentWord.replace(/┬╖/, "" )
  9486.         this._currentWord=this._currentWord.replace(/"/g, "" )
  9487.         this._currentWord=this._currentWord.replace(/'/, "%27" )
  9488.  
  9489.         if (this._eventButton==2&&this._shiftKey) { //Shift key
  9490.             if (!WikiLookdb_pref.getBoolPref("WikiLookShiftEnabled")) { /*this.clearAll();*/ return};;
  9491.             this._currentParser = WikiLookdb_pref.getCharPref("WikiLookShiftParser");
  9492.             evt.preventDefault();
  9493.             evt.stopPropagation();
  9494.             if (this._currentParser == 'native') {
  9495.                 this.nativeParser();
  9496.             } else {
  9497.                 if (WikiLookdb_pref.getBoolPref("WikiLookShiftSmartLookupEnabled")&&this._currentParser.indexOf("wiktionary")==-1){this.GoogleIt(); return};
  9498.                 pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9499.                 setSiteInfo();
  9500.                 setMainRegex();
  9501.                 setTitleBase();
  9502.                 setNamespaces();
  9503.                 setRegexps();
  9504.                 if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9505.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9506.                 this._CSS='<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopsft.css" /> ';
  9507.                 a.href=this._currentParser+"/wiki/"+this._currentWord;
  9508.                 if (!this._insideDivLookup) this.clearDisplay();
  9509.                 this._DIVclass='sft';
  9510.                 mouseOverWikiLink2(a);
  9511.                 this.clearKeys();
  9512.             }
  9513.         } else {
  9514.             if (this._eventButton==2&&this._altKey) { //ALT key
  9515.                 if (!WikiLookdb_pref.getBoolPref("WikiLookAltEnabled")) { /*this.clearAll();*/ return};
  9516.                 this._currentParser = WikiLookdb_pref.getCharPref("WikiLookAltParser");
  9517.                 evt.preventDefault();
  9518.                 evt.stopPropagation();
  9519.                 if (this._currentParser == 'native') {
  9520.                     this.nativeParser();
  9521.                 } else {
  9522.                     if (WikiLookdb_pref.getBoolPref("WikiLookAltSmartLookupEnabled")&&this._currentParser.indexOf("wiktionary")==-1){this.GoogleIt(); return};                                    pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9523.                     setSiteInfo();
  9524.                     setMainRegex();
  9525.                     setTitleBase();
  9526.                     setNamespaces();
  9527.                     setRegexps();
  9528.                     if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9529.                     var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9530.                     this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopalt.css" /> ';
  9531.                     a.href=this._currentParser+"/wiki/"+this._currentWord;
  9532.                     if (!this._insideDivLookup) this.clearDisplay();
  9533.                     this._DIVclass='alt';
  9534.                     mouseOverWikiLink2(a);
  9535.                     this.clearKeys();
  9536.                 }
  9537.             }  else { 
  9538.                 if (this._eventButton==2&&this._ctrlKey) { //CTRL key
  9539.                     if (!WikiLookdb_pref.getBoolPref("WikiLookCtrlEnabled")) { /*this.clearAll();*/ return};;
  9540.                     this._currentParser = WikiLookdb_pref.getCharPref("WikiLookCtrlParser");
  9541.                     evt.preventDefault();
  9542.                     evt.stopPropagation();
  9543.                     if (this._currentParser == 'native') {
  9544.                         this.nativeParser(); 
  9545.                     } else {
  9546.                         if (WikiLookdb_pref.getBoolPref("WikiLookCtrlSmartLookupEnabled")&&this._currentParser.indexOf("wiktionary")==-1){this.GoogleIt(); return};
  9547.                         pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9548.                         setSiteInfo();
  9549.                         setMainRegex();
  9550.                         setTitleBase();
  9551.                         setNamespaces();
  9552.                         setRegexps();
  9553.                         if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9554.                         var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9555.                         this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopctl.css" /> ';
  9556.                         a.href=this._currentParser+"/wiki/"+this._currentWord;
  9557.                         if (!this._insideDivLookup) this.clearDisplay();
  9558.                         this._DIVclass='ctl';
  9559.                         mouseOverWikiLink2(a);
  9560.                         this.clearKeys();
  9561.                     }
  9562.                 } else { //here we run event that binded to mousecall property
  9563.                     if (!WikiLookdb_pref.getBoolPref("WikiLookMouselookEnabled")) { /*this.clearAll();*/ return};
  9564.  
  9565.                     try {    
  9566.                         if (typeof evt.originalTarget.childNodes[1]!="undefined"&&typeof evt.originalTarget.childNodes[1].offsetParent!="undefined") {
  9567.                             if (evt.originalTarget.parentNode.parentNode.id.indexOf("navpopup_maindiv")==0||evt.originalTarget.parentNode.id.indexOf("navpopup_maindiv")==0||evt.originalTarget.childNodes[1].offsetParent.id.indexOf("navpopup_maindiv")==0||evt.originalTarget.offsetParent.id.indexOf("navpopup_maindiv")==0) {
  9568.                                 this._insideDivLookup=true;
  9569.                             } else {
  9570.                                 this._insideDivLookup=false;
  9571.                             }
  9572.                         } else {    
  9573.                             if (evt.originalTarget.parentNode.parentNode.id.indexOf("navpopup_maindiv")==0||evt.originalTarget.parentNode.id.indexOf("navpopup_maindiv")==0||evt.originalTarget.offsetParent.id.indexOf("navpopup_maindiv")==0) {
  9574.                                 this._insideDivLookup=true;
  9575.                             } else {
  9576.                                 this._insideDivLookup=false;
  9577.                             }
  9578.                         }    
  9579.                     } catch (err) { this._insideDivLookup=false; }    
  9580.                     
  9581.                     this._currentParser = WikiLookdb_pref.getCharPref("WikiLookMouselookParser");
  9582.                     if (this._currentParser == 'native') {
  9583.                         this.nativeParser() 
  9584.                     } else {
  9585.                         if (WikiLookdb_pref.getBoolPref("WikiLookMouselookSmartLookupEnabled")&&this._currentParser.indexOf("wiktionary")==-1){this.GoogleIt(); return};
  9586.                         pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9587.                         setSiteInfo();
  9588.                         setMainRegex();
  9589.                         setTitleBase();
  9590.                         setNamespaces();
  9591.                         setRegexps();
  9592.                         if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9593.                         var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9594.                         this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopmic.css" /> ';
  9595.                         a.href=this._currentParser+"/wiki/"+this._currentWord;
  9596.                         if (!this._insideDivLookup) this.clearDisplay();
  9597.                         this._DIVclass='mic';
  9598.                         mouseOverWikiLink2(a);
  9599.                         this.clearKeys();
  9600.                     }
  9601.                 }    
  9602.             }    
  9603.         }    
  9604.     }
  9605. }
  9606.  
  9607. WikiLook.prototype.GoogleIt = function () {
  9608.     try    {
  9609.         WL_request = new XMLHttpRequest();
  9610.         if (WL_request.readyState != 0) {
  9611.             return;
  9612.         }
  9613.         var url="http://www.google.com/search?hl=en&q=site%3A"+this._currentParser+"/wiki/+"+this._currentWord.replace(" ","+");
  9614.         WL_request.open("GET", url, true);
  9615.         WL_request.send(null);
  9616.     }
  9617.     catch (e)    {
  9618.         return;
  9619.     }
  9620.  
  9621.     WL_request.onreadystatechange = function() {
  9622.         if (WL_request!=null) {
  9623.             if (WL_request.readyState == 4) {
  9624.                 if (WL_request.status==200||WL_request.status==404) {
  9625.                     WikiLook_Overlay.GoogleIt2(WL_request.responseText);
  9626.                 }
  9627.             }
  9628.         }
  9629.     }
  9630. }
  9631.  
  9632. WikiLook.prototype.GoogleIt2 = function (text) {
  9633.     var gURLStart='href="'+(this._currentParser)+'/wiki/';
  9634.     if (text.indexOf(gURLStart)!=-1) {
  9635.         this._currentWord=text.substring(text.indexOf(gURLStart)+gURLStart.length, text.indexOf(gURLStart)+gURLStart.length+500);
  9636.         this._currentWord=this._currentWord.substring(0,this._currentWord.indexOf('"'))
  9637.         this._currentWord=decodeURI(this._currentWord);
  9638.         this._currentWord=this._currentWord.replace("<b>", "", "gi");
  9639.         this._currentWord=this._currentWord.replace("</b>", "", "gi");
  9640.     } 
  9641.             if (this._eventButton==2&&this._shiftKey) { //Shift key
  9642.             if (this._currentParser == 'native') {
  9643.                 this.nativeParser();
  9644.             } else {
  9645.                 pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9646.                 setSiteInfo();
  9647.                 setMainRegex();
  9648.                 setTitleBase();
  9649.                 setNamespaces();
  9650.                 setRegexps();
  9651.                 if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9652.                 var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9653.                 this._CSS='<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopsft.css" /> ';
  9654.                 a.href=this._currentParser+"/wiki/"+this._currentWord;
  9655.                 if (!this._insideDivLookup) this.clearDisplay();
  9656.                 this._DIVclass='sft';
  9657.                 mouseOverWikiLink2(a);
  9658.                 this.clearKeys();
  9659.             }
  9660.         } else {
  9661.             if (this._eventButton==2&&this._altKey) { //ALT key
  9662.                 if (this._currentParser == 'native') {
  9663.                     this.nativeParser();
  9664.                 } else {
  9665.                     pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9666.                     setSiteInfo();
  9667.                     setMainRegex();
  9668.                     setTitleBase();
  9669.                     setNamespaces();
  9670.                     setRegexps();
  9671.                     if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9672.                     var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9673.                     this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopalt.css" /> ';
  9674.                     a.href=this._currentParser+"/wiki/"+this._currentWord;
  9675.                     if (!this._insideDivLookup) this.clearDisplay();
  9676.                     this._DIVclass='alt';
  9677.                     mouseOverWikiLink2(a);
  9678.                     this.clearKeys();
  9679.                 }
  9680.             }  else { 
  9681.                 if (this._eventButton==2&&this._ctrlKey) { //CTRL key
  9682.                     if (this._currentParser == 'native') {
  9683.                         this.nativeParser(); 
  9684.                     } else {
  9685.                         pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9686.                         setSiteInfo();
  9687.                         setMainRegex();
  9688.                         setTitleBase();
  9689.                         setNamespaces();
  9690.                         setRegexps();
  9691.                         if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9692.                         var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9693.                         this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopctl.css" /> ';
  9694.                         a.href=this._currentParser+"/wiki/"+this._currentWord;
  9695.                         if (!this._insideDivLookup) this.clearDisplay();
  9696.                         this._DIVclass='ctl';
  9697.                         mouseOverWikiLink2(a);
  9698.                         this.clearKeys();
  9699.                     }
  9700.                 } else { //here we run event that binded to mousecall property
  9701.                     if (this._currentParser == 'native') {
  9702.                         this.nativeParser() 
  9703.                     } else {
  9704.                         pg.wiki.hostname=this._currentParser.substring(7,this._currentParser.length);
  9705.                         setSiteInfo();
  9706.                         setMainRegex();
  9707.                         setTitleBase();
  9708.                         setNamespaces();
  9709.                         setRegexps();
  9710.                         if (this._currentParser.indexOf("wiktionary")!=-1&&this._currentParser.indexOf("de.wiktionary")==-1) this._currentWord=this._currentWord.toLowerCase();
  9711.                         var a=document.createElementNS("http://www.w3.org/1999/xhtml",'a');
  9712.                         this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopmic.css" /> ';
  9713.                         a.href=this._currentParser+"/wiki/"+this._currentWord;
  9714.                         if (!this._insideDivLookup) this.clearDisplay();
  9715.                         this._DIVclass='mic';
  9716.                         mouseOverWikiLink2(a);
  9717.                         this.clearKeys();
  9718.                     }
  9719.                 }    
  9720.             }    
  9721.         }
  9722. }
  9723.  
  9724.  
  9725.  
  9726.  
  9727. WikiLook.prototype.nativeParser = function () {
  9728.     if (!this._insideDivLookup) this.clearDisplay();
  9729.     this._showDefinition = true;
  9730.     this._thisIsAFormOf=false;
  9731.     if(!this.attachDiv()) return;
  9732.     this._div.style.left = this.getNewWindowX()+"px";
  9733.     this._div.style.top = this.getNewWindowY()+"px";
  9734.     this._div.innerHTML = this._CSS + "(looking up <b>"+ this._currentWord.replace("%27","\'" ) +"</b> from Wiktionary.org ...)";
  9735.     if (this._div != null && this._showDefinition == true) {
  9736.         this._div.style.display="block";
  9737.     }
  9738.     
  9739.     this._isRequestFetching = true;
  9740.     this.requestFetchWord(this._currentWord);
  9741.     this.clearKeys();
  9742. }
  9743.  
  9744.  
  9745. WikiLook.prototype.getNewWindowX = function () {
  9746.     if (this._eventClientX + 400  + this._pref_WindowOffsetX > this._currentDoc.width ) {
  9747.         return (this._currentDoc.width - 400 > 0) ? (this._currentDoc.width - 400) : 0;
  9748.     }
  9749.     else {
  9750.         return this._eventClientX + this._pref_WindowOffsetX;
  9751.     }
  9752. }
  9753.  
  9754. WikiLook.prototype.getNewWindowY = function () {
  9755.     return this._eventClientY + this._currentDoc.documentElement.scrollTop + this._currentDoc.body.scrollTop + this._pref_WindowOffsetY;
  9756. }
  9757.  
  9758. WikiLook.prototype.showDiv = function () {
  9759.     if (this._div != null && this._showDefinition == true) {
  9760.         this._div.style.display="block";
  9761.         this._divIsDisplayed = true;
  9762.     }
  9763. }
  9764.  
  9765. WikiLook.prototype.hideDiv = function() {
  9766.     if (this._div != null) {
  9767.         this._div.style.display="none";
  9768.     }
  9769.     this._divIsDisplayed = false;
  9770. }
  9771.  
  9772. WikiLook.prototype.openWLOptions = function() { WikiLook_Overlay.openWLOptionsImpl(); }
  9773. WikiLook.prototype.openWLOptionsImpl  = function() {
  9774.         if (window.navigator.userAgent.indexOf("Mac OS")!=-1) {
  9775.             window.openDialog('chrome://wikilook/content/optionsmac.xul', null, 'chrome,centerscreen,dependent');
  9776.         } else {
  9777.             window.openDialog('chrome://wikilook/content/optionsnorm.xul', null, 'chrome,centerscreen,dependent');
  9778.         }
  9779. }
  9780.  
  9781. WikiLook.prototype.WLmakeDraggable = function() {
  9782.     if (!this._div) { this.WLcreateMainDiv(); }
  9783.     var drag=new Drag();
  9784.  
  9785.         drag.startCondition=function(e) {
  9786.         try { if (e.shiftKey||e.target.href != null/*||e.target.toString()=="[object HTMLSpanElement]"*/) { return false; } } catch (err) { return false; }
  9787.         return true;
  9788.         };
  9789.     
  9790.     var dragHandle = this._div;
  9791.     var np=this;
  9792.     drag.endHook=function(x,y) {
  9793.     };
  9794.     drag.init(dragHandle,this._div);
  9795. };
  9796.     
  9797. WikiLook.prototype.shortcatsWikiLook = function(event) { WikiLook_Overlay.shortcatsWikiLookImpl(event); }
  9798. WikiLook.prototype.shortcatsWikiLookImpl  = function(evt) {
  9799.  
  9800.     var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which);
  9801.     if (keyCode==27) { // escape
  9802.         //this.clearAll();
  9803.         if (this._divQ[0]!=null) {
  9804.             //this._currentDoc.body.removeChild(this._currentDoc.getElementById(this._divQ[0]));
  9805.             this.removeDivPrp(this._divQ[0]);
  9806.             this._divQ.splice(0,1);
  9807.             return;
  9808.         }
  9809.     }
  9810.     if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); }
  9811. }
  9812.  
  9813. WikiLook.prototype.attachDiv = function() {
  9814.     if (this._showDefinition == false) {
  9815.         return false;
  9816.     }
  9817.     if (this._thisIsAFormOf==true) {
  9818.         return true;
  9819.     }
  9820.     var div;
  9821.     if (document.onkeypress!=this.shortcatsWikiLook) {
  9822.         document.oldPopupOnkeypress=document.onkeypress;
  9823.     }
  9824.  
  9825.     document.onkeypress=this.shortcatsWikiLook;
  9826.     
  9827.     this.WLcreateMainDiv();
  9828.     
  9829.     setTimeout(function(){WikiLook_Overlay.WLmakeDraggable();}, 150);
  9830.  
  9831.     this._DIVrepositioned=false;
  9832.  
  9833.     return true;
  9834. }
  9835.  
  9836. WikiLook.prototype.WLcreateMainDiv = function() {
  9837.     var mainDiv=document.createElementNS("http://www.w3.org/1999/xhtml",'div');
  9838.  
  9839.     var savedThis=this;
  9840.     mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv';
  9841.     mainDiv.id=mainDiv.className + this.uid;
  9842.     this.uid=this.uid+1;
  9843.     mainDiv.style.position='absolute';
  9844.     mainDiv.className='WikiLook';
  9845.     mainDiv.style.maxWidth = "450px";
  9846.     mainDiv.style.zIndex=this._divZIndex + 1;
  9847.     ++this._divZIndex;
  9848.     this._div=mainDiv;
  9849.     this._divId=mainDiv.id;
  9850.     
  9851.     content.document.body.appendChild(mainDiv);
  9852.     this._CSS = '<link rel="stylesheet" type="text/css" href="chrome://wikilook/content/navpopntv.css" /> ';
  9853.     this._divQ.unshift(this._divId);
  9854.     //this.runHooks('create', 'after');
  9855. }
  9856.  
  9857. WikiLook.prototype.removeDivPrp = function(divID) {
  9858.     try {this._currentDoc.getElementById(divID).parentNode.removeChild(this._currentDoc.getElementById(divID));}
  9859.     catch (err) {
  9860.         var doc = content.document;
  9861.         var body = doc.body;
  9862.         var div = doc.getElementById(divID);
  9863.         body.removeChild(div);
  9864.     }
  9865.     //this._insideDivLookup=false;
  9866. }
  9867.  
  9868.  
  9869. WikiLook.prototype.removeDiv = function() {
  9870.     
  9871.     document.onkeypress=document.oldPopupOnkeypress;
  9872.     if (this._div != null) {
  9873.         try {
  9874.             this.removeDivPrp(this._divId);
  9875.             this._divQ.splice(0,1);
  9876.             
  9877.         }
  9878.         catch (err) {
  9879.         }
  9880.         this._divIsDisplayed = false;
  9881.         this._div = null;
  9882.     }
  9883.  
  9884.     try {
  9885.         if (this._currentDoc.getElementById(this._divId) != null) {
  9886.             var t=this._currentDoc.getElementById(this._divId).parentNode;
  9887.             t.removeChild(this._currentDoc.getElementById(this._divId));
  9888.             this._currentDoc.removeChild(this._divId);
  9889.             this._divQ.splice(0,1);
  9890.         }
  9891.     }
  9892.     catch (err) {
  9893.     }
  9894.     this._divIsDisplayed = false;
  9895.     this._div = null;
  9896. }
  9897.  
  9898. WikiLook.prototype.toCapitalCaseWL = function(words) {
  9899. var re = /\s/;
  9900. words = words.split(re);
  9901. re = /(\S)(\S+)/;
  9902. for (i = words.length - 1; i >= 0; i--) {
  9903. re.exec(words[i]);
  9904. words[i] = RegExp.$1.toUpperCase()
  9905. + RegExp.$2.toLowerCase();
  9906. }
  9907. return words.join(' ');
  9908. }
  9909.  
  9910.  
  9911.  
  9912.  
  9913.  
  9914. WikiLook.prototype.responseFetch2 = function (response) {
  9915.     this._goForIt=true;
  9916.     if (this._en_wikt.responseFetchReal(response)==true||this._divIsDisplayed == true){
  9917.         return;
  9918.     }    else {
  9919.             this._div.innerHTML = "<link rel='stylesheet' type='text/css' href='chrome://wikilook/content/navpopntv.css' />* Unable to parse the <a style=\"color:"+this._linkColor+";\" href='http://en.wiktionary.org/wiki/"+this._currentWord+"'>" + this._currentWord.toLowerCase() + "</a> from <a  href=http://en.wiktionary.org>wiktionary.org</a>";
  9920.             this._WL_unable=true;
  9921.             //Killing "unable to parse" div in  1 sec
  9922.             setTimeout(function(something) { return function() { WikiLook_Overlay.removeDiv(); WikiLook_Overlay._WL_unable=false; WikiLook_Overlay.clearAllButScreen(); }; }(this), 1000);
  9923.     }
  9924.     
  9925. }
  9926.  
  9927.  
  9928.  
  9929. WikiLook.prototype.responseFetch = function (response) {
  9930.     this._defFound=false;
  9931.     this._mainLngFound=false;
  9932.     this._goForIt=false;
  9933.     this._engDefFound=false;
  9934.     this._outTextForFormOf="";
  9935.     this._divIsDisplayed=false; //???
  9936.     this._thisIsAFormOf=false;
  9937.     this._thisIsAFormOfFormOf=false;
  9938.     this._audioLinkShown=false;    
  9939.     if (this._en_wikt.responseFetchReal(response)==true){
  9940.         return;
  9941.     }    else {
  9942.             if (this._currentWord==this._currentWord.toUpperCase()) {
  9943.                 this._currentWord=this._currentWord.toLowerCase();
  9944.             } else {
  9945.                 if (this._currentWord==this.toCapitalCaseWL(this._currentWord)) {
  9946.                     this._currentWord=this._currentWord.toLowerCase();
  9947.                 } else {
  9948.                     this._currentWord=this.toCapitalCaseWL(this._currentWord);
  9949.                 };
  9950.             }
  9951.             if (this._defFound == false) {this._isRequestFetching = true; }
  9952.             this.requestFetchWord2(this._currentWord);
  9953.     }
  9954.     return;
  9955. }
  9956.  
  9957.  
  9958.  
  9959.  
  9960. WikiLook.prototype.requestFetchWord = function (word) {
  9961.  
  9962.  
  9963.     try    {
  9964.         WL_request = new XMLHttpRequest();
  9965.         if (WL_request.readyState != 0) {
  9966.             return;
  9967.         }
  9968.         var url="http://en.wiktionary.org/wiki/"+ word;
  9969.         WL_request.open("GET", url, true);
  9970.         WL_request.send(null);
  9971.     }
  9972.     catch (e)    {
  9973.         return;
  9974.     }
  9975.  
  9976.     WL_request.onreadystatechange = function() {
  9977.         if (WL_request!=null) {
  9978.             if (WL_request.readyState == 4) {
  9979.                 if (WL_request.status==200||WL_request.status==404) {
  9980.                     WikiLook_Overlay.responseFetch(WL_request.responseText);
  9981. //                                        alert('debug');
  9982.                 }
  9983.             }
  9984.         }
  9985.     }
  9986. }
  9987.  
  9988. WikiLook.prototype.requestFetchWord2 = function (word) {
  9989.     try    {
  9990.         WL_request = new XMLHttpRequest();
  9991.         if (WL_request.readyState != 0) {
  9992.             return;
  9993.         }
  9994.         var url="http://en.wiktionary.org/wiki/"+ word;
  9995.         WL_request.open("GET", url, true);
  9996.         WL_request.send(null);
  9997.     }
  9998.     catch (e)    {
  9999.         return;
  10000.     }
  10001.  
  10002.     WL_request.onreadystatechange = function() {
  10003.         if (WL_request!=null) {
  10004.             if (WL_request.readyState == 4) {
  10005.                 if (WL_request.status==200||WL_request.status==404) {
  10006.                     if (WikiLook_Overlay._div.innerHTML.indexOf(" autoplay")!=-1 ){ 
  10007.                     setTimeout(function() {
  10008.                         WikiLook_Overlay.responseFetch2(WL_request.responseText);;},
  10009.                     900);
  10010.                     } else {
  10011.                         WikiLook_Overlay.responseFetch2(WL_request.responseText);
  10012.                     }
  10013.                 }
  10014.             }
  10015.         }
  10016.     }
  10017. }
  10018.  
  10019.  
  10020.  
  10021. WikiLook.prototype.wiktionarySetStyle = function (str) {
  10022. /**Ported back from the fork*/
  10023.     // Fix styles of links that link to external websites
  10024.     str = str.replace(/ href="([^\/#])/g, ' class="WikiLook WikiLookExternalLink" href="$1');
  10025.     // Remove texts like (A date for this quote is being sought)
  10026.     str = str.replace(/<span class="rfdate">\(<span class="rfdate-text"[\w\W]*?<\/span>\)<span class="rfdate-colon">:<\/span><\/span>/g, "");
  10027.     // Fix all internal links so they will link to wiktionary
  10028.     str = str.replace(/ href="\//g, ' href="http://en.wiktionary.org/');
  10029.     // Fix links containing #
  10030.     str = str.replace(/ href="#/g, ' href="http://en.wiktionary.org/wiki/' + this.currentWord + '#');
  10031.     // Fix font size and color of context labels (e.g. "(slang)") included using templates
  10032.     str = str.replace(/<span class="ib-brac"><span class="qualifier-brac">\((.[^\)]*?)(<a href=)(.*?)\)/g, '<span class="ib-brac"><span class="qualifier-brac">($1<a class="WikiLookContextLink" href=$3)');
  10033.     str = str.replace(/<span class="ib-brac"><span class="qualifier-brac">\(<\/span><\/span><span class="ib-content"><span class="qualifier-content">(.*?)<\/span><\/span><span class="ib-brac"><span class="qualifier-brac">\)<\/span><\/span>/g, '<font class="WikiLookContextLabel">$1</font>');
  10034.     // Fix font size and color of context labels without links that were included incorretly
  10035.     str = str.replace(/(<li>|<\/font>)(.*)(?:<i>\(|\(<i>)(.*)(?:\)<\/i>|<\/i>\))/g, '$1$2<font class="WikiLookContextLabel">$3</font>');
  10036.     // Fix links to pages that haven't been written yet
  10037.     str = str.replace(/<a (href="http:\/\/[^\.]+\.wiktionary\.org\/w\/index\.php\?title=[^&]*&action=edit&redlink=1")/g, '<a class="WikiLook WikiLookRedLink" $1');
  10038.     // Fix font size and color of context labels with links that were included incorretly, i.e. not using templates
  10039.     str = str.replace(/<a href="http:\/\/en\.wiktionary\.org\/wiki\/Appendix:Glossary([^>]*)>/g, '<a class="WikiLookContextLink" href="http://en.wiktionary.org/wiki/Appendix:Glossary$1">');
  10040.     // Set <a> classes that were not set as "WikiLookContextLink" or "WikiLookRedLink"
  10041.     str = str.replace(/<a href=/g, '<a class="WikiLook" href=');
  10042.     // Set classes to WikiLook
  10043.     str = str.replace(/<(i|b|ol|dl|dd|li|ul|table|tbody|tr|td)>/g, '<$1 class="WikiLook">');
  10044.     str = str.replace(/<(b|td|ul) style="/g, '<$1 class="WikiLook" style="');
  10045.     str = str.replace(/<sup[^>]*>/g, '<sup class="WikiLook">');
  10046.     // Set image caption classes
  10047.     str = str.replace(/<div class="thumbcaption">/g, '<div class="WikiLookImageCaption">');
  10048.     str = str.replace(/<div class="thumb(?: tright| tleft)"[^>]*>/g, '<div class="WikiLook">');
  10049.     str = str.replace(/<div class="thumbinner"([^>]*)>/g, '<div class="WikiLookImg"$1>');
  10050.     // Remove texts like "Can we verify this sense?" and "Should we delete this redundant sense"
  10051.     str = str.replace(/<span style="color:#777777">([\w\W]*?)<\/span>/g, "");
  10052.     // Remove the "enlarge" button under every image. Clicking the image itself does the same thing
  10053.     str = str.replace(/<div class="magnify">[\w\W]*?<\/div>/g, "");
  10054.     // Remove all <cite>
  10055.     str = str.replace(/<(?:\/?)cite(?:[^>]*)>/g, "");
  10056.     return str;
  10057.     //var nomargin = "color:#000000;padding:0px 1px 1px 1px;margin:1px 1px 1px 4px;font-weight:normal;";
  10058.     //stxt = stxt.replace("<ol>","<ol style='padding:2px 2px 2px 10px;margin:2px 2px 2px 10px;'>","gi");
  10059.     //stxt = stxt.replace("<dl style='","<dl style='"+nomargin+";","gi");
  10060.     //stxt = stxt.replace("<dl>","<dl style='"+nomargin+";'>","gi");
  10061.     //stxt = stxt.replace("<dd style='","<dd style='"+nomargin+";","gi");
  10062.     //stxt = stxt.replace("<dd>","<dd style='"+nomargin+";'>","gi");
  10063.     //stxt = stxt.replace("<li style='","<li style='"+nomargin+";font-family:arial;","gi");
  10064.     //Next lines are non essential lines that looks for "lazy mans" inclusion of context labels, ones that defined not by tamplate, but by parentheses. 
  10065.     //stxt = stxt.replace(/<li>\(<i>([^\)]*)<\/i>\)/g, "<li><i><font size=-7 color=\"purple\">($1)</font></i>");
  10066.     //stxt = stxt.replace(/<li>(\([^\)]*\))/g, "<li><i><font size=-7 color=\"purple\">$1</font></i>");
  10067.     //Formatting  actual context labels
  10068.     //stxt = stxt.replace(/<span class="ib-comma"><span class="qualifier-comma">,<\/span><\/span>/g, ",");
  10069.     //to fix font size /color of links inside parenteses
  10070.     //stxt = stxt.replace(/<span class="ib-brac"><span class="qualifier-brac">\((.[^\)]*?)(<a href=)(.*?)\)/gi, "<span class=\"ib-brac\"><span class=\"qualifier-brac\">($1<a style=\"color:brown;font-size:9px;\" href=$3)"); 
  10071.     //stxt = stxt.replace(/<span class="ib-brac"><span class="qualifier-brac">\((.[^\)]*?)(<a href=)(.*?)\)/g, "<span class=\"ib-brac\"><span class=\"qualifier-brac\">($1<a style=\"color:brown;font-size:9px;\" href=$3)"); 
  10072.     //stxt = stxt.replace(/<span class="ib-brac"><span class="qualifier-brac">\((.[^\)]*?)(<a href=)(.*?)\)/g, "<span class=\"ib-brac\"><span class=\"qualifier-brac\">($1<a style=\"color:brown;font-size:9px;\" href=$3)"); 
  10073.     //stxt = stxt.replace(/<span class="ib-brac"><span class="qualifier-brac">\(<\/span><\/span><span class="ib-content"><span class="qualifier-content">(.*?)<\/span><\/span><span class="ib-brac"><span class="qualifier-brac">\)<\/span><\/span>/g, "<i><font size=-7 color=\"purple\">($1)</font></i>"); 
  10074.     //stxt = stxt.replace("<li>","<li style='"+nomargin+";font-family:arial;list-style-image:none;line-height:100%;background-color:"+this._backgroundColor+";'>","gi");
  10075.     //stxt = stxt.replace("<li>","<liWikiLook>","gi");
  10076.     //stxt = stxt.replace("</li>","</liWikiLook>","gi");    
  10077.     //stxt = stxt.replace("<i>","<i style='color:#000000;font-weight:normal;font-family:arial;list-style-type:none;line-height:100%;background-color:"+this._backgroundColor+"'>","gi");
  10078.     //fixinf heperlink font size/color of the  links
  10079.     //stxt = stxt.replace(/ href=/g, " style=\"color:"+this._linkColor+";font-weight:normal;font-size:12px;\" href="); 
  10080.     //return stxt;
  10081. }
  10082.  
  10083.  
  10084.  
  10085. WikiLook.prototype.getCurrentWord = function(parent, offset, target) {
  10086.     var container = parent.parentNode;
  10087.     if (container) {
  10088.             var foundNode = false;
  10089.             for (var c = container.firstChild; c != null; c = c.nextSibling) {
  10090.                     if (c == parent) {
  10091.                             foundNode = true;
  10092.                             break;
  10093.                     }
  10094.             }
  10095.             if (!foundNode) {
  10096.                     return null;
  10097.             }
  10098.     }
  10099.     var range = parent.ownerDocument.createRange();
  10100.     range.selectNode(parent);
  10101.     var str = range.toString();
  10102.     if (offset < 0 || offset >= str.length) {
  10103.             return null;
  10104.     }
  10105.     var start = offset;
  10106.     var end = offset + 1;
  10107.     var valid_chars = /[0-9a-zA-Z╨░-╤Å╨É-╨»├á-┼╛╬æ-ß┐Ñ╘▒-╓çπüü-πâ╢Σ┐â-µ¥üπä▒-φòÿΓü┐'ΓÇÖ├ƒ┼┐├£├ä├ü├ë├ì-]/;
  10108.     if (!valid_chars.test(str.substring(start, start + 1))) {
  10109.             return null;
  10110.     }
  10111.     while (start > 0) {
  10112.             if (valid_chars.test(str.substring(start - 1, start))) {
  10113.                     start--;
  10114.             } else {
  10115.                     break;
  10116.             }
  10117.     }
  10118.     while (end < str.length) {
  10119.             if (valid_chars.test(str.substring(end, end + 1))) {
  10120.                     end++;
  10121.             } else {
  10122.                     break;
  10123.             }
  10124.     }
  10125.     var prottext = str.substring(start, end);
  10126.     if(prottext.indexOf("d'")==0) {prottext=prottext.substring(2,prottext.length);}
  10127.     if(prottext.indexOf("dΓÇÖ")==0) {prottext=prottext.substring(2,prottext.length);}
  10128.     if(prottext.indexOf("l'")==0) {prottext=prottext.substring(2,prottext.length);}
  10129.     if(prottext.indexOf("lΓÇÖ")==0) {prottext=prottext.substring(2,prottext.length);}
  10130.     if(prottext.indexOf("D'")==0) {prottext=prottext.substring(2,prottext.length);}
  10131.     if(prottext.indexOf("DΓÇÖ")==0) {prottext=prottext.substring(2,prottext.length);}
  10132.     if(prottext.indexOf("L'")==0) {prottext=prottext.substring(2,prottext.length);}
  10133.     if(prottext.indexOf("LΓÇÖ")==0) {prottext=prottext.substring(2,prottext.length);}
  10134.     
  10135.     var selection = document.commandDispatcher.focusedWindow.getSelection();
  10136.     var mouseInSelection = (!selection.isCollapsed && selection.getRangeAt(0).isPointInRange(parent, offset));
  10137.     var selectedText = selection.toString();
  10138.     if (selectedText.length>50||(mouseInSelection&&(selectedText.length==0))) return null;
  10139.     valid_chars = /[0-9a-zA-Z╨░-╤Å╨É-╨»├á-┼╛╬æ-ß┐Ñ╘▒-╓çπüü-πâ╢Σ┐â-µ¥üπä▒-φòÿΓü┐'ΓÇÖ├ƒ┼┐├£├ä├ü├ë├ì]/;
  10140.     while (!valid_chars.test(selectedText[selectedText.length-1])&&selectedText.length>2) {
  10141.         selectedText=selectedText.substring(0,selectedText.length-1);
  10142.     }
  10143.     while (!valid_chars.test(selectedText[0])&&selectedText.length>2) {
  10144.         selectedText=selectedText.substring(1,selectedText.length);
  10145.     }
  10146.     if (mouseInSelection&&(this._eventButton==0||this._eventButton==null)&&(!this._altKey||!this._ctrlKey||!this._shiftKey)) return selectedText; 
  10147.     if (mouseInSelection&&(this._eventButton==2)&&(this._altKey||this._ctrlKey||this._shiftKey)) return selectedText
  10148.     if  (((this._eventButton==2)&&(this._altKey||this._ctrlKey||this._shiftKey))&&prottext.length>0) return prottext;
  10149.     if (this._shiftKey&&prottext.length>0) return prottext;
  10150.     return null;
  10151. };
  10152.  
  10153.  
  10154. WikiLook.prototype.plainText = function(text_) {
  10155.     var text = WL_HTMLEncode(text_);
  10156.     text = text.replace(/\n/g, "<BR />");
  10157.     return text;
  10158. }
  10159.  
  10160. WikiLook.prototype.HTMLEncode = function(text) {
  10161.     text = text.replace(/&/g, "&");
  10162.     text = text.replace(/"/g, """);
  10163.     text = text.replace(/</g, "<");
  10164.     text = text.replace(/>/g, ">");
  10165.     text = text.replace(/'/g, "’");
  10166.     return text;
  10167. }
  10168.  
  10169. WikiLook.prototype.HTMLDecode = function(text) {
  10170.     text = text.replace(/&/g, "&");
  10171.     text = text.replace(/"/g, "\"");
  10172.     text = text.replace(/</g, "<");
  10173.     text = text.replace(/>/g, ">");
  10174.     text = text.replace(/’/g, "'");
  10175.     text = text.replace(/<BR \/>/g, "\n");
  10176.     return text;
  10177. }
  10178.  
  10179. WikiLook.prototype.getTop = function(div){
  10180.     return parseInt(div.style.top.substr(0, div.style.top.length-2))
  10181. }
  10182.  
  10183. WikiLook.prototype.getLeft = function(div){
  10184.     return parseInt(div.style.left.substr(0, div.style.left.length-2))
  10185. }
  10186.  
  10187. WikiLook.prototype.stripHTML = function(oldString) {
  10188.     var newString = "";
  10189.     var inTag = false;
  10190.     for(var i = 0; i < oldString.length; i++) {
  10191.         if(oldString.charAt(i) == '<') inTag = true;
  10192.         if(oldString.charAt(i) == '>') {
  10193.             inTag = false;
  10194.             i++;
  10195.         }
  10196.         if(!inTag) newString += oldString.charAt(i);
  10197.     }
  10198.     return newString;
  10199. }
  10200.  
  10201. WikiLook.prototype.stripTags = function(oldString) {
  10202.     return oldString.replace(/(<([^>]+)>)/ig,"");
  10203. }
  10204.  
  10205.  
  10206. WikiLook.prototype.cutHead_preserve = function(strPattern, oldString) {
  10207.     i = oldString.indexOf(strPattern);
  10208.     if (i==-1) {
  10209.         return null;
  10210.     } else {
  10211.         return oldString.substring(i);
  10212.     }
  10213. }
  10214.  
  10215.  
  10216. WikiLook.prototype.cutTail_preserve = function(strPattern, oldString) {
  10217.     i = oldString.indexOf(strPattern);
  10218.     if (i==-1) {
  10219.         return null;
  10220.     } else {
  10221.         return oldString.substring(0, i + strPattern.length);
  10222.     }
  10223. }
  10224.  
  10225. /**
  10226.  *Trim whitespace from the edges of strings
  10227. **/
  10228. WikiLook.prototype.trim = function (str) {
  10229.     //removes 
  10230.     // the start (^) followed by lots of whitespace (s+)
  10231.     // or (|) 
  10232.     // lots of whitespace (s+) followed by the end ($)
  10233.       return str.replace (/^\s+|\s+$/g, "");
  10234. }
  10235.  
  10236.  
  10237.